WifiServiceImpl.java revision 3b26801d62a06475b722bbf29cba7f48f376654e
1d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor/*
2d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * Copyright (C) 2010 The Android Open Source Project
3d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor *
4d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * Licensed under the Apache License, Version 2.0 (the "License");
5d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * you may not use this file except in compliance with the License.
6d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * You may obtain a copy of the License at
7d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor *
8d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor *      http://www.apache.org/licenses/LICENSE-2.0
9d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor *
10d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * Unless required by applicable law or agreed to in writing, software
11d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * distributed under the License is distributed on an "AS IS" BASIS,
12d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * See the License for the specific language governing permissions and
14d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * limitations under the License.
15d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor */
16d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor
1730a2e16f6c27f888dd11eba6bbbae1e980078fcbChandler Carruthpackage com.android.server.wifi;
18d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor
19d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.app.ActivityManager;
20d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregorimport android.app.AppOpsManager;
21d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.bluetooth.BluetoothAdapter;
22d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.BroadcastReceiver;
23d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.Context;
24d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.Intent;
25d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.IntentFilter;
26d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.pm.PackageManager;
27d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.content.pm.UserInfo;
28d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.database.ContentObserver;
29d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.DhcpInfo;
30d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.DhcpResults;
31d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.IpConfiguration.ProxySettings;
32d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.LinkAddress;
33d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.NetworkUtils;
34d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.RouteInfo;
35d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.wifi.*;
36d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.net.wifi.IWifiManager;
37d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.AsyncTask;
38d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.Binder;
39d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.Handler;
40d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.HandlerThread;
41d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.IBinder;
4224bae92f08ae098cc50a602d8cf1273b423e14daDouglas Gregorimport android.os.Message;
43c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport android.os.Messenger;
44c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport android.os.RemoteException;
45c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport android.os.SystemProperties;
46d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.os.UserHandle;
47357bbd022c1d340c8e255aea7a684ddb34bc76e5Douglas Gregorimport android.os.UserManager;
48686775deca8b8685eb90801495880e3abdd844c2Chris Lattnerimport android.os.WorkSource;
49d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.provider.Settings;
50d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.util.Log;
51d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport android.util.Slog;
52d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor
53d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.io.FileNotFoundException;
54d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.io.BufferedReader;
55357bbd022c1d340c8e255aea7a684ddb34bc76e5Douglas Gregorimport java.io.FileDescriptor;
56d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport java.io.FileReader;
5724bae92f08ae098cc50a602d8cf1273b423e14daDouglas Gregorimport java.io.IOException;
58d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.io.PrintWriter;
59d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.lang.Override;
60d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.net.InetAddress;
61d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.net.Inet4Address;
62d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.util.ArrayList;
63d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport java.util.List;
64d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor
65d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport com.android.internal.R;
66d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregorimport com.android.internal.app.IBatteryStats;
67c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport com.android.internal.telephony.TelephonyIntents;
68c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport com.android.internal.util.AsyncChannel;
69d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport com.android.server.am.BatteryStatsService;
70d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregor
71d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
72d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
73d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
74d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
75d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
76d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
77d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
78c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smithimport static com.android.server.wifi.WifiController.CMD_SET_AP;
79d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
80d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregorimport static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
81d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregor/**
82d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * WifiService handles remote WiFi operation requests by implementing
83d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor * the IWifiManager interface.
84d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor *
85d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor * @hide
86d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor */
87d3731198193eee92796ddeb493973b7a598b003eDouglas Gregorpublic final class WifiServiceImpl extends IWifiManager.Stub {
88c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smith    private static final String TAG = "WifiService";
89d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    private static final boolean DBG = true;
90c95d413660756c474bc8f97e5b32edc7ddff3850Richard Smith
91d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    final WifiStateMachine mWifiStateMachine;
92d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor
93d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    private final Context mContext;
94d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor
95d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor    final LockList mLocks = new LockList();
96d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor    // some wifi lock statistics
97b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mFullHighPerfLocksAcquired;
98b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mFullHighPerfLocksReleased;
9924bae92f08ae098cc50a602d8cf1273b423e14daDouglas Gregor    private int mFullLocksAcquired;
100b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mFullLocksReleased;
101b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mScanLocksAcquired;
102b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mScanLocksReleased;
103b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith
104b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private final List<Multicaster> mMulticasters =
105b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith            new ArrayList<Multicaster>();
106b5eb3f5bf383807103dc1377a124fd96ee21d02aRichard Smith    private int mMulticastEnabled;
107d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregor    private int mMulticastDisabled;
10824bae92f08ae098cc50a602d8cf1273b423e14daDouglas Gregor
10924bae92f08ae098cc50a602d8cf1273b423e14daDouglas Gregor    private final IBatteryStats mBatteryStats;
110d6350aefb1396b299e199c7f1fe51bb40c12e75eDouglas Gregor    private final AppOpsManager mAppOps;
111d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor
1128a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    private String mInterfaceName;
1138a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor
1147cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall    /* Tracks the open wi-fi network notification */
1158a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    private WifiNotificationController mNotificationController;
1168a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    /* Polls traffic stats and notifies clients */
1178a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    private WifiTrafficPoller mTrafficPoller;
1188a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    /* Tracks the persisted states for wi-fi & airplane mode */
1198a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    final WifiSettingsStore mSettingsStore;
1208a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor
1218a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    final boolean mBatchedScanSupported;
1228a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor
1238a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor    /**
1248a51491d936d8c50480f3c3ca6647be12a7ad51fDouglas Gregor     * Asynchronous channel to WifiStateMachine
12502024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor     */
1267cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall    private AsyncChannel mWifiStateMachineChannel;
1277cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall
1287cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall    /**
1297cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall     * Handles client connections
1307cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall     */
1317cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall    private class ClientHandler extends Handler {
1327cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall
1337cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall        ClientHandler(android.os.Looper looper) {
1347cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall            super(looper);
1357cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall        }
1367cd088e519d7e6caa4c4c12db52e0e4ae35d25c2John McCall
13702024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor        @Override
13802024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor        public void handleMessage(Message msg) {
13902024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor            switch (msg.what) {
14002024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
14102024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
14202024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                        if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
14302024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                        // We track the clients by the Messenger
14402024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                        // since it is expected to be always available
14502024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                        mTrafficPoller.addClient(msg.replyTo);
14602024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    } else {
14702024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                        Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
14802024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    }
14902024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    break;
15002024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                }
15102024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
15202024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
153d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                        if (DBG) Slog.d(TAG, "Send failed, client connection lost");
154855243789cb44799c03f4c7216d3d6308805f549Benjamin Kramer                    } else {
155855243789cb44799c03f4c7216d3d6308805f549Benjamin Kramer                        if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
15602024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    }
15702024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    mTrafficPoller.removeClient(msg.replyTo);
158855243789cb44799c03f4c7216d3d6308805f549Benjamin Kramer                    break;
15902024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                }
16002024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
16102024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    AsyncChannel ac = new AsyncChannel();
16202024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    ac.connect(mContext, this, msg.replyTo);
16302024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    break;
16402024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                }
16502024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                /* Client commands are forwarded to state machine */
16602024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                case WifiManager.CONNECT_NETWORK:
16702024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                case WifiManager.SAVE_NETWORK: {
16802024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    WifiConfiguration config = (WifiConfiguration) msg.obj;
16902024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    int networkId = msg.arg1;
17002024a9f0d8e6c898de276193af604c42ee41269Douglas Gregor                    if (msg.what == WifiManager.SAVE_NETWORK) {
1712a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        if (config != null) {
1722a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1732a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                config.creatorUid = Binder.getCallingUid();
1742a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            } else {
1752a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                config.lastUpdateUid = Binder.getCallingUid();
1762a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            }
1772a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        }
1782a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        Slog.e("WiFiServiceImpl ", "SAVE"
17912c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                                + " nid=" + Integer.toString(networkId)
18012c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                                + " uid=" + Integer.toString(config.creatorUid)
18187d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                                + "/" + Integer.toString(config.lastUpdateUid));
18287d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    }
18312c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                    if (msg.what == WifiManager.CONNECT_NETWORK) {
1842a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        if (config != null) {
1852a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1862a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                config.creatorUid = Binder.getCallingUid();
1872a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            } else {
1883bbffd549c76dfeb3c8d7c73860736a6523cde92Benjamin Kramer                                config.lastUpdateUid = Binder.getCallingUid();
1893bbffd549c76dfeb3c8d7c73860736a6523cde92Benjamin Kramer                            }
1903bbffd549c76dfeb3c8d7c73860736a6523cde92Benjamin Kramer                        }
1913bbffd549c76dfeb3c8d7c73860736a6523cde92Benjamin Kramer                        Slog.e("WiFiServiceImpl ", "CONNECT "
1922a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                + " nid=" + Integer.toString(networkId)
1932a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                + " uid=" + Binder.getCallingUid());
1942a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    }
1952a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    if (config != null && config.isValid()) {
1962a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        if (DBG) Slog.d(TAG, "Connect with config" + config);
1972a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        mWifiStateMachine.sendMessage(Message.obtain(msg));
1982a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    } else if (config == null
1992a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
2002a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
2012a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        mWifiStateMachine.sendMessage(Message.obtain(msg));
2022a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    } else {
2032a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
2042a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        if (msg.what == WifiManager.CONNECT_NETWORK) {
2052a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                            replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
20612c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                                    WifiManager.INVALID_ARGS);
20712c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                        } else {
20812c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                            replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
20912c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                                    WifiManager.INVALID_ARGS);
21012c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                        }
2112a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    }
21212c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                    break;
213686775deca8b8685eb90801495880e3abdd844c2Chris Lattner                }
21412c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                case WifiManager.FORGET_NETWORK:
2152a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    if (isOwner(msg.sendingUid)) {
2162a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        mWifiStateMachine.sendMessage(Message.obtain(msg));
2172a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    } else {
2182a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        Slog.e(TAG, "Forget is not authorized for user");
2192a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        replyFailed(msg, WifiManager.FORGET_NETWORK_FAILED,
2202a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                                WifiManager.NOT_AUTHORIZED);
2212a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    }
2222a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    break;
2232a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                case WifiManager.START_WPS:
2242a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                case WifiManager.CANCEL_WPS:
2252a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                case WifiManager.DISABLE_NETWORK:
2262a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                case WifiManager.RSSI_PKTCNT_FETCH: {
227d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                    mWifiStateMachine.sendMessage(Message.obtain(msg));
228d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                    break;
229d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                }
230d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                default: {
231d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                    Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
232d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                    break;
233d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                }
234d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor            }
235d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        }
236d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor
237d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        private void replyFailed(Message msg, int what, int why) {
238d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor            Message reply = msg.obtain();
239d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor            reply.what = what;
2402a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall            reply.arg1 = why;
241be2fa7ebf01259b63dc52fe46c8d101c18e72269Craig Topper            try {
2420e2c34f92f00628d48968dfea096d36381f494cbStephen Hines                msg.replyTo.send(reply);
2430e2c34f92f00628d48968dfea096d36381f494cbStephen Hines            } catch (RemoteException e) {
2442a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                // There's not much we can do if reply can't be sent!
2452a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall            }
2462a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        }
2472a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall    }
248d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    private ClientHandler mClientHandler;
2496bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
2502a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall    /**
2512a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall     * Handles interaction with WifiStateMachine
2522a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall     */
2532a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall    private class WifiStateMachineHandler extends Handler {
2542a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        private AsyncChannel mWsmChannel;
2552a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall
2562a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        WifiStateMachineHandler(android.os.Looper looper) {
257d8e54990ade0dd5566f8e3aa2e62def08753d1e9Chris Lattner            super(looper);
258d8e54990ade0dd5566f8e3aa2e62def08753d1e9Chris Lattner            mWsmChannel = new AsyncChannel();
2592a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall            mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
2602a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        }
2612a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall
2622a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        @Override
2632a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        public void handleMessage(Message msg) {
2642a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall            switch (msg.what) {
26512c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
26612c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
26712c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                        mWifiStateMachineChannel = mWsmChannel;
2682a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    } else {
2692a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
2702a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                        mWifiStateMachineChannel = null;
2712a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                    }
27223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                    break;
27323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                }
27423323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
27523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                    Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
2763ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    mWifiStateMachineChannel = null;
2773ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    //Re-establish connection to state machine
2783ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
2793ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                    break;
2803ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar                }
28123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                default: {
28223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                    Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
28323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                    break;
2846bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                }
28523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins            }
28623323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        }
28723323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    }
28823323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
28923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    WifiStateMachineHandler mWifiStateMachineHandler;
29023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
29123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    private WifiWatchdogStateMachine mWifiWatchdogStateMachine;
29223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
29323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    private WifiController mWifiController;
29423323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
29523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    public WifiServiceImpl(Context context) {
29623323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mContext = context;
29723323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
29823323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mInterfaceName =  SystemProperties.get("wifi.interface", "wlan0");
29923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
30023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mTrafficPoller = new WifiTrafficPoller(mContext, mInterfaceName);
30123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mWifiStateMachine = new WifiStateMachine(mContext, mInterfaceName, mTrafficPoller);
30223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mWifiStateMachine.enableRssiPolling(true);
30323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mBatteryStats = BatteryStatsService.getService();
30423323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
30523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
30623323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mNotificationController = new WifiNotificationController(mContext, mWifiStateMachine);
3073ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar        mSettingsStore = new WifiSettingsStore(mContext);
3083ea9e33ea25e0c2b12db56418ba3f994eb662c04Pirama Arumuga Nainar
30923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        HandlerThread wifiThread = new HandlerThread("WifiService");
31023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        wifiThread.start();
31123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mClientHandler = new ClientHandler(wifiThread.getLooper());
31223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mWifiStateMachineHandler = new WifiStateMachineHandler(wifiThread.getLooper());
31323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
31423323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
31523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        mBatchedScanSupported = mContext.getResources().getBoolean(
31623323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins                R.bool.config_wifi_batched_scan_supported);
31723323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    }
31823323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
31923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
32023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    /**
32123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins     * Check if Wi-Fi needs to be enabled and start
32223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins     * if needed
32312c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor     *
32412c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor     * This function is used only at boot time
32512c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor     */
32612c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor    public void checkAndStartWifi() {
32712c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor        /* Check if wi-fi needs to be enabled */
32812c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor        boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
329c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
33012c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                (wifiEnabled ? "enabled" : "disabled"));
33112c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor
33212c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor        registerForScanModeChange();
3332a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall        mContext.registerReceiver(
3342a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall                new BroadcastReceiver() {
33587d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar                    @Override
33612c9c00024a01819e3a70ef6d951d32efaeb9312Douglas Gregor                    public void onReceive(Context context, Intent intent) {
337d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                        if (mSettingsStore.handleAirplaneModeToggled()) {
338d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
339d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                        }
340d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                    }
341d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                },
342d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
343d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor
344d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        // Adding optimizations of only receiving broadcasts when wifi is enabled
345d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        // can result in race conditions when apps toggle wifi in the background
346d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        // without active user involvement. Always receive broadcasts.
347d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        registerForBroadcasts();
348d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor
349d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        mWifiController.start();
350d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor
351d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        // If we are already disabled (could be due to airplane mode), avoid changing persist
352d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        // state here
35322eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor        if (wifiEnabled) setWifiEnabled(wifiEnabled);
35422eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor
35522eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor        mWifiWatchdogStateMachine = WifiWatchdogStateMachine.
35622eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor               makeWifiWatchdogStateMachine(mContext, mWifiStateMachine.getMessenger());
35722eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor    }
3586bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines
3596bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines    /**
36022eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor     * see {@link android.net.wifi.WifiManager#pingSupplicant()}
36122eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor     * @return {@code true} if the operation succeeds, {@code false} otherwise
36222eaced5cac3cf0522c953f593419fc6cf184aafDouglas Gregor     */
363d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor    public boolean pingSupplicant() {
364d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        enforceAccessPermission();
365d3731198193eee92796ddeb493973b7a598b003eDouglas Gregor        if (mWifiStateMachineChannel != null) {
3666bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
3676bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        } else {
3686bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
3692a7fb27913999d132cf9e10e03dc5271faa2e9d3John McCall            return false;
370d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        }
371d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    }
3728491ffe86c50241b47c6d7ef8cd9ee00f5e675daDouglas Gregor
3738491ffe86c50241b47c6d7ef8cd9ee00f5e675daDouglas Gregor    /**
374d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor     * see {@link android.net.wifi.WifiManager#getChannelList}
3758491ffe86c50241b47c6d7ef8cd9ee00f5e675daDouglas Gregor     */
376d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    public List<WifiChannel> getChannelList() {
377d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        enforceAccessPermission();
37823323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        if (mWifiStateMachineChannel != null) {
37923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins            return mWifiStateMachine.syncGetChannelList(mWifiStateMachineChannel);
380d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        } else {
381d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
382d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            return null;
383d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        }
384686775deca8b8685eb90801495880e3abdd844c2Chris Lattner    }
385d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor
386d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    /**
387d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor     * see {@link android.net.wifi.WifiManager#startScan}
388ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo     * and {@link android.net.wifi.WifiManager#startCustomizedScan}
389ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo     *
390ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo     * @param settings If null, use default parameter, i.e. full scan.
391ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo     * @param workSource If null, all blame is given to the calling uid.
392ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo     */
393ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo    public void startScan(ScanSettings settings, WorkSource workSource) {
394ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        enforceChangePermission();
395ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        if (settings != null) {
396d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            // TODO: should be removed once the startCustomizedScan API is opened up
397d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.LOCATION_HARDWARE,
398d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                    "LocationHardware");
399612409ece080e814f79e06772c690d603f45fbd6Richard Smith            settings = new ScanSettings(settings);
400612409ece080e814f79e06772c690d603f45fbd6Richard Smith            if (!settings.isValid()) {
4016bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                Slog.e(TAG, "invalid scan setting");
4026bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines                return;
403d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            }
404ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        }
405ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        if (workSource != null) {
406ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            enforceWorkSourcePermission();
407ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            // WifiManager currently doesn't use names, so need to clear names out of the
408ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            // supplied WorkSource to allow future WorkSource combining.
409ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            workSource.clearNames();
410ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        }
411ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        mWifiStateMachine.startScan(Binder.getCallingUid(), settings, workSource);
412ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman    }
413ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman
414ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman    private class BatchedScanRequest extends DeathRecipient {
415ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        final BatchedScanSettings settings;
41687d948ecccffea9e9e37d0d053b246e2d6d6c47bPirama Arumuga Nainar        final int uid;
417ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        final int pid;
418ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        final WorkSource workSource;
419ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman
420ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        BatchedScanRequest(BatchedScanSettings settings, IBinder binder, WorkSource ws) {
421ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            super(0, null, binder, null);
422ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            this.settings = settings;
423ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            this.uid = getCallingUid();
424ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            this.pid = getCallingPid();
425ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            workSource = ws;
426ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        }
427ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        public void binderDied() {
428ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            stopBatchedScan(settings, uid, pid);
429ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        }
430d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        public String toString() {
431ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
432af0f4d0b2e38c810effc8b024ad2fb6604eec5d3Francois Pichet        }
433ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman
434ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman        public boolean isSameApp(int uid, int pid) {
435ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman            return (this.uid == uid && this.pid == pid);
436567f917df048d42732997a479b2b257403fc88efLarisse Voufo        }
437ded9979a2997336cee8797deb6bb3194fccc2068Eli Friedman    }
43823323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
43923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
44023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
44123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    public boolean isBatchedScanSupported() {
44223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        return mBatchedScanSupported;
44323323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    }
44423323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
44523323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    public void pollBatchedScan() {
44623323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        enforceChangePermission();
4476bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        if (mBatchedScanSupported == false) return;
4486bcf27bb9a4b5c3f79cb44c0e4654a6d7619ad89Stephen Hines        mWifiStateMachine.requestBatchedScanPoll();
44923323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    }
45023323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins
45123323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins    public String getWpsNfcConfigurationToken(int netId) {
45223323e0253716ff03c95a00fb6903019daafe3aaDeLesley Hutchins        enforceConnectivityInternalPermission();
453d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        return mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId);
454686775deca8b8685eb90801495880e3abdd844c2Chris Lattner    }
455d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor
456d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    /**
457d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor     * see {@link android.net.wifi.WifiManager#requestBatchedScan()}
458d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor     */
459ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo    public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder,
460ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            WorkSource workSource) {
461ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        enforceChangePermission();
462ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        if (workSource != null) {
463d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            enforceWorkSourcePermission();
464d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            // WifiManager currently doesn't use names, so need to clear names out of the
465d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            // supplied WorkSource to allow future WorkSource combining.
466d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            workSource.clearNames();
467d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        }
468d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        if (mBatchedScanSupported == false) return false;
469d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        requested = new BatchedScanSettings(requested);
470d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        if (requested.isInvalid()) return false;
471ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        BatchedScanRequest r = new BatchedScanRequest(requested, binder, workSource);
472ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        synchronized(mBatchedScanners) {
473ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            mBatchedScanners.add(r);
474ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            resolveBatchedScannersLocked();
475d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        }
476d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        return true;
477d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    }
478d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor
479d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    public List<BatchedScanResult> getBatchedScanResults(String callingPackage) {
480d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        enforceAccessPermission();
481d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>();
482d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        int uid = Binder.getCallingUid();
483ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        int userId = UserHandle.getCallingUserId();
484ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        long ident = Binder.clearCallingIdentity();
485ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        try {
486ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
487d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                    != AppOpsManager.MODE_ALLOWED) {
488d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                return new ArrayList<BatchedScanResult>();
489686775deca8b8685eb90801495880e3abdd844c2Chris Lattner            }
490d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            if (!isCurrentProfile(userId)) {
491d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                return new ArrayList<BatchedScanResult>();
492d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            }
493d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            return mWifiStateMachine.syncGetBatchedScanResultsList();
494d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        } finally {
495d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            Binder.restoreCallingIdentity(ident);
496d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        }
497d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    }
498d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor
499d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor    public void stopBatchedScan(BatchedScanSettings settings) {
500ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        enforceChangePermission();
501ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        if (mBatchedScanSupported == false) return;
502ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo        stopBatchedScan(settings, getCallingUid(), getCallingPid());
503ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo    }
504c568f1e98938584c0ef0b12ae5018ff7d90a4072Stephen Hines
505ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo    private void stopBatchedScan(BatchedScanSettings settings, int uid, int pid) {
5063e4c6c4c79a03f5cb0c4671d7c282d623c6dc35eRichard Smith        ArrayList<BatchedScanRequest> found = new ArrayList<BatchedScanRequest>();
507d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor        synchronized(mBatchedScanners) {
508d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor            for (BatchedScanRequest r : mBatchedScanners) {
509d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                if (r.isSameApp(uid, pid) && (settings == null || settings.equals(r.settings))) {
510d65587f7a6d38965fa37158d3f57990a7faf3836Douglas Gregor                    found.add(r);
511ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo                    if (settings != null) break;
512ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo                }
513ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            }
514ef4579cda09b73e3d4d98af48201da25adc29326Larisse Voufo            for (BatchedScanRequest r : found) {
515f1c66b40213784a1c4612f04c14cafa2b0e89988Richard Smith                mBatchedScanners.remove(r);
5168491ffe86c50241b47c6d7ef8cd9ee00f5e675daDouglas Gregor            }
517d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor            if (found.size() != 0) {
518d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor                resolveBatchedScannersLocked();
519d1102433214bd33b5bef5b493944292a1e82c2fbDouglas Gregor            }
520        }
521    }
522
523    private void resolveBatchedScannersLocked() {
524        BatchedScanSettings setting = new BatchedScanSettings();
525        WorkSource responsibleWorkSource = null;
526        int responsibleUid = 0;
527        double responsibleCsph = 0; // Channel Scans Per Hour
528
529        if (mBatchedScanners.size() == 0) {
530            mWifiStateMachine.setBatchedScanSettings(null, 0, 0, null);
531            return;
532        }
533        for (BatchedScanRequest r : mBatchedScanners) {
534            BatchedScanSettings s = r.settings;
535
536            // evaluate responsibility
537            int currentChannelCount;
538            int currentScanInterval;
539            double currentCsph;
540
541            if (s.channelSet == null || s.channelSet.isEmpty()) {
542                // all channels - 11 B and 9 A channels roughly.
543                currentChannelCount = 9 + 11;
544            } else {
545                currentChannelCount = s.channelSet.size();
546                // these are rough est - no real need to correct for reg-domain;
547                if (s.channelSet.contains("A")) currentChannelCount += (9 - 1);
548                if (s.channelSet.contains("B")) currentChannelCount += (11 - 1);
549
550            }
551            if (s.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
552                currentScanInterval = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
553            } else {
554                currentScanInterval = s.scanIntervalSec;
555            }
556            currentCsph = 60 * 60 * currentChannelCount / currentScanInterval;
557
558            if (currentCsph > responsibleCsph) {
559                responsibleUid = r.uid;
560                responsibleWorkSource = r.workSource;
561                responsibleCsph = currentCsph;
562            }
563
564            if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
565                    s.maxScansPerBatch < setting.maxScansPerBatch) {
566                setting.maxScansPerBatch = s.maxScansPerBatch;
567            }
568            if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
569                    (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED ||
570                    s.maxApPerScan > setting.maxApPerScan)) {
571                setting.maxApPerScan = s.maxApPerScan;
572            }
573            if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
574                    s.scanIntervalSec < setting.scanIntervalSec) {
575                setting.scanIntervalSec = s.scanIntervalSec;
576            }
577            if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
578                    (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED ||
579                    s.maxApForDistance > setting.maxApForDistance)) {
580                setting.maxApForDistance = s.maxApForDistance;
581            }
582            if (s.channelSet != null && s.channelSet.size() != 0) {
583                if (setting.channelSet == null || setting.channelSet.size() != 0) {
584                    if (setting.channelSet == null) setting.channelSet = new ArrayList<String>();
585                    for (String i : s.channelSet) {
586                        if (setting.channelSet.contains(i) == false) setting.channelSet.add(i);
587                    }
588                } // else, ignore the constraint - we already use all channels
589            } else {
590                if (setting.channelSet == null || setting.channelSet.size() != 0) {
591                    setting.channelSet = new ArrayList<String>();
592                }
593            }
594        }
595
596        setting.constrain();
597        mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid, (int)responsibleCsph,
598                responsibleWorkSource);
599    }
600
601    private void enforceAccessPermission() {
602        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
603                "WifiService");
604    }
605
606    private void enforceChangePermission() {
607        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
608                                                "WifiService");
609
610    }
611
612    private void enforceReadCredentialPermission() {
613        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
614                                                "WifiService");
615    }
616
617    private void enforceWorkSourcePermission() {
618        mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
619                "WifiService");
620
621    }
622
623    private void enforceMulticastChangePermission() {
624        mContext.enforceCallingOrSelfPermission(
625                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
626                "WifiService");
627    }
628
629    private void enforceConnectivityInternalPermission() {
630        mContext.enforceCallingOrSelfPermission(
631                android.Manifest.permission.CONNECTIVITY_INTERNAL,
632                "ConnectivityService");
633    }
634
635    /**
636     * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
637     * @param enable {@code true} to enable, {@code false} to disable.
638     * @return {@code true} if the enable/disable operation was
639     *         started or is already in the queue.
640     */
641    public synchronized boolean setWifiEnabled(boolean enable) {
642        enforceChangePermission();
643        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
644                    + ", uid=" + Binder.getCallingUid());
645        if (DBG) {
646            Slog.e(TAG, "Invoking mWifiStateMachine.setWifiEnabled\n");
647        }
648
649        /*
650        * Caller might not have WRITE_SECURE_SETTINGS,
651        * only CHANGE_WIFI_STATE is enforced
652        */
653
654        long ident = Binder.clearCallingIdentity();
655        try {
656            if (! mSettingsStore.handleWifiToggled(enable)) {
657                // Nothing to do if wifi cannot be toggled
658                return true;
659            }
660        } finally {
661            Binder.restoreCallingIdentity(ident);
662        }
663
664        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
665        return true;
666    }
667
668    /**
669     * see {@link WifiManager#getWifiState()}
670     * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
671     *         {@link WifiManager#WIFI_STATE_DISABLING},
672     *         {@link WifiManager#WIFI_STATE_ENABLED},
673     *         {@link WifiManager#WIFI_STATE_ENABLING},
674     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
675     */
676    public int getWifiEnabledState() {
677        enforceAccessPermission();
678        return mWifiStateMachine.syncGetWifiState();
679    }
680
681    /**
682     * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
683     * @param wifiConfig SSID, security and channel details as
684     *        part of WifiConfiguration
685     * @param enabled true to enable and false to disable
686     */
687    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
688        enforceChangePermission();
689        UserManager um = UserManager.get(mContext);
690        if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
691            throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
692        }
693        // null wifiConfig is a meaningful input for CMD_SET_AP
694        if (wifiConfig == null || wifiConfig.isValid()) {
695            mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
696        } else {
697            Slog.e(TAG, "Invalid WifiConfiguration");
698        }
699    }
700
701    /**
702     * see {@link WifiManager#getWifiApState()}
703     * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
704     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
705     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
706     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
707     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
708     */
709    public int getWifiApEnabledState() {
710        enforceAccessPermission();
711        return mWifiStateMachine.syncGetWifiApState();
712    }
713
714    /**
715     * see {@link WifiManager#getWifiApConfiguration()}
716     * @return soft access point configuration
717     */
718    public WifiConfiguration getWifiApConfiguration() {
719        enforceAccessPermission();
720        return mWifiStateMachine.syncGetWifiApConfiguration();
721    }
722
723    /**
724     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
725     * @param wifiConfig WifiConfiguration details for soft access point
726     */
727    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
728        enforceChangePermission();
729        if (wifiConfig == null)
730            return;
731        if (wifiConfig.isValid()) {
732            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
733        } else {
734            Slog.e(TAG, "Invalid WifiConfiguration");
735        }
736    }
737
738    /**
739     * @param enable {@code true} to enable, {@code false} to disable.
740     * @return {@code true} if the enable/disable operation was
741     *         started or is already in the queue.
742     */
743    public boolean isScanAlwaysAvailable() {
744        enforceAccessPermission();
745        return mSettingsStore.isScanAlwaysAvailable();
746    }
747
748    /**
749     * see {@link android.net.wifi.WifiManager#disconnect()}
750     */
751    public void disconnect() {
752        enforceChangePermission();
753        mWifiStateMachine.disconnectCommand();
754    }
755
756    /**
757     * see {@link android.net.wifi.WifiManager#reconnect()}
758     */
759    public void reconnect() {
760        enforceChangePermission();
761        mWifiStateMachine.reconnectCommand();
762    }
763
764    /**
765     * see {@link android.net.wifi.WifiManager#reassociate()}
766     */
767    public void reassociate() {
768        enforceChangePermission();
769        mWifiStateMachine.reassociateCommand();
770    }
771
772    /**
773     * see {@link android.net.wifi.WifiManager#getAdaptors}
774     */
775    public List<WifiAdapter> getAdaptors() {
776        enforceAccessPermission();
777        if (mWifiStateMachineChannel != null) {
778            return mWifiStateMachine.syncGetAdaptors(mWifiStateMachineChannel);
779        } else {
780            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
781            return null;
782        }
783    }
784
785    /**
786     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
787     * @return the list of configured networks
788     */
789    public List<WifiConfiguration> getConfiguredNetworks() {
790        enforceAccessPermission();
791        if (mWifiStateMachineChannel != null) {
792            return mWifiStateMachine.syncGetConfiguredNetworks(mWifiStateMachineChannel);
793        } else {
794            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
795            return null;
796        }
797    }
798
799    /**
800     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
801     * @return the list of configured networks with real preSharedKey
802     */
803    public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
804        enforceReadCredentialPermission();
805        enforceAccessPermission();
806        if (mWifiStateMachineChannel != null) {
807            return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
808        } else {
809            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
810            return null;
811        }
812    }
813
814    /**
815     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
816     * @return the supplicant-assigned identifier for the new or updated
817     * network if the operation succeeds, or {@code -1} if it fails
818     */
819    public int addOrUpdateNetwork(WifiConfiguration config) {
820        enforceChangePermission();
821        if (config.isValid()) {
822            //TODO: pass the Uid the WifiStateMachine as a message parameter
823            Slog.e("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
824                    + " SSID " + config.SSID
825                    + " nid=" + Integer.toString(config.networkId));
826            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
827                config.creatorUid = Binder.getCallingUid();
828            } else {
829                config.lastUpdateUid = Binder.getCallingUid();
830            }
831            if (mWifiStateMachineChannel != null) {
832                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
833            } else {
834                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
835                return -1;
836            }
837        } else {
838            Slog.e(TAG, "bad network configuration");
839            return -1;
840        }
841    }
842
843     /**
844     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
845     * @param netId the integer that identifies the network configuration
846     * to the supplicant
847     * @return {@code true} if the operation succeeded
848     */
849    public boolean removeNetwork(int netId) {
850        enforceChangePermission();
851
852        if (!isOwner(Binder.getCallingUid())) {
853            Slog.e(TAG, "Remove is not authorized for user");
854            return false;
855        }
856
857        if (mWifiStateMachineChannel != null) {
858            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
859        } else {
860            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
861            return false;
862        }
863    }
864
865    /**
866     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
867     * @param netId the integer that identifies the network configuration
868     * to the supplicant
869     * @param disableOthers if true, disable all other networks.
870     * @return {@code true} if the operation succeeded
871     */
872    public boolean enableNetwork(int netId, boolean disableOthers) {
873        enforceChangePermission();
874        if (mWifiStateMachineChannel != null) {
875            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
876                    disableOthers);
877        } else {
878            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
879            return false;
880        }
881    }
882
883    /**
884     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
885     * @param netId the integer that identifies the network configuration
886     * to the supplicant
887     * @return {@code true} if the operation succeeded
888     */
889    public boolean disableNetwork(int netId) {
890        enforceChangePermission();
891        if (mWifiStateMachineChannel != null) {
892            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
893        } else {
894            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
895            return false;
896        }
897    }
898
899    /**
900     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
901     * @return the Wi-Fi information, contained in {@link WifiInfo}.
902     */
903    public WifiInfo getConnectionInfo() {
904        enforceAccessPermission();
905        /*
906         * Make sure we have the latest information, by sending
907         * a status request to the supplicant.
908         */
909        return mWifiStateMachine.syncRequestConnectionInfo();
910    }
911
912    /**
913     * Return the results of the most recent access point scan, in the form of
914     * a list of {@link ScanResult} objects.
915     * @return the list of results
916     */
917    public List<ScanResult> getScanResults(String callingPackage) {
918        enforceAccessPermission();
919        int userId = UserHandle.getCallingUserId();
920        int uid = Binder.getCallingUid();
921        long ident = Binder.clearCallingIdentity();
922        try {
923            if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
924                    != AppOpsManager.MODE_ALLOWED) {
925                return new ArrayList<ScanResult>();
926            }
927            if (!isCurrentProfile(userId)) {
928                return new ArrayList<ScanResult>();
929            }
930            return mWifiStateMachine.syncGetScanResultsList();
931        } finally {
932            Binder.restoreCallingIdentity(ident);
933        }
934    }
935
936    /**
937     * Returns true if the calling user is the current one or a profile of the
938     * current user..
939     */
940    private boolean isCurrentProfile(int userId) {
941        int currentUser = ActivityManager.getCurrentUser();
942        if (userId == currentUser) {
943            return true;
944        }
945        List<UserInfo> profiles = UserManager.get(mContext).getProfiles(currentUser);
946        for (UserInfo user : profiles) {
947            if (userId == user.id) {
948                return true;
949            }
950        }
951        return false;
952    }
953
954    /**
955     * Returns true if uid is an application running under the owner or a profile of the owner.
956     *
957     * Note: Should not be called if identity is cleared.
958     */
959    private boolean isOwner(int uid) {
960        long ident = Binder.clearCallingIdentity();
961        int userId = UserHandle.getUserId(uid);
962        try {
963            int ownerUser = UserHandle.USER_OWNER;
964            if (userId == ownerUser) {
965                return true;
966            }
967            List<UserInfo> profiles = UserManager.get(mContext).getProfiles(ownerUser);
968            for (UserInfo profile : profiles) {
969                if (userId == profile.id) {
970                    return true;
971                }
972            }
973            return false;
974        }
975        finally {
976            Binder.restoreCallingIdentity(ident);
977        }
978    }
979
980
981    /**
982     * Tell the supplicant to persist the current list of configured networks.
983     * @return {@code true} if the operation succeeded
984     *
985     * TODO: deprecate this
986     */
987    public boolean saveConfiguration() {
988        boolean result = true;
989        enforceChangePermission();
990        if (mWifiStateMachineChannel != null) {
991            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
992        } else {
993            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
994            return false;
995        }
996    }
997
998    /**
999     * Set the country code
1000     * @param countryCode ISO 3166 country code.
1001     * @param persist {@code true} if the setting should be remembered.
1002     *
1003     * The persist behavior exists so that wifi can fall back to the last
1004     * persisted country code on a restart, when the locale information is
1005     * not available from telephony.
1006     */
1007    public void setCountryCode(String countryCode, boolean persist) {
1008        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1009                " with persist set to " + persist);
1010        enforceConnectivityInternalPermission();
1011        final long token = Binder.clearCallingIdentity();
1012        try {
1013            mWifiStateMachine.setCountryCode(countryCode, persist);
1014        } finally {
1015            Binder.restoreCallingIdentity(token);
1016        }
1017    }
1018
1019    /**
1020     * Set the operational frequency band
1021     * @param band One of
1022     *     {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
1023     *     {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ},
1024     *     {@link WifiManager#WIFI_FREQUENCY_BAND_2GHZ},
1025     * @param persist {@code true} if the setting should be remembered.
1026     *
1027     */
1028    public void setFrequencyBand(int band, boolean persist) {
1029        enforceChangePermission();
1030        if (!isDualBandSupported()) return;
1031        Slog.i(TAG, "WifiService trying to set frequency band to " + band +
1032                " with persist set to " + persist);
1033        final long token = Binder.clearCallingIdentity();
1034        try {
1035            mWifiStateMachine.setFrequencyBand(band, persist);
1036        } finally {
1037            Binder.restoreCallingIdentity(token);
1038        }
1039    }
1040
1041
1042    /**
1043     * Get the operational frequency band
1044     */
1045    public int getFrequencyBand() {
1046        enforceAccessPermission();
1047        return mWifiStateMachine.getFrequencyBand();
1048    }
1049
1050    public boolean isDualBandSupported() {
1051        //TODO: Should move towards adding a driver API that checks at runtime
1052        return mContext.getResources().getBoolean(
1053                com.android.internal.R.bool.config_wifi_dual_band_support);
1054    }
1055
1056    /**
1057     * Return the DHCP-assigned addresses from the last successful DHCP request,
1058     * if any.
1059     * @return the DHCP information
1060     * @deprecated
1061     */
1062    public DhcpInfo getDhcpInfo() {
1063        enforceAccessPermission();
1064        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1065
1066        DhcpInfo info = new DhcpInfo();
1067
1068        if (dhcpResults.ipAddress != null &&
1069                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1070            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1071        }
1072
1073        if (dhcpResults.gateway != null) {
1074            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1075        }
1076
1077        int dnsFound = 0;
1078        for (InetAddress dns : dhcpResults.dnsServers) {
1079            if (dns instanceof Inet4Address) {
1080                if (dnsFound == 0) {
1081                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1082                } else {
1083                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1084                }
1085                if (++dnsFound > 1) break;
1086            }
1087        }
1088        InetAddress serverAddress = dhcpResults.serverAddress;
1089        if (serverAddress instanceof Inet4Address) {
1090            info.serverAddress = NetworkUtils.inetAddressToInt((Inet4Address)serverAddress);
1091        }
1092        info.leaseDuration = dhcpResults.leaseDuration;
1093
1094        return info;
1095    }
1096
1097    /**
1098     * see {@link android.net.wifi.WifiManager#startWifi}
1099     *
1100     */
1101    public void startWifi() {
1102        enforceConnectivityInternalPermission();
1103        /* TODO: may be add permissions for access only to connectivity service
1104         * TODO: if a start issued, keep wifi alive until a stop issued irrespective
1105         * of WifiLock & device idle status unless wifi enabled status is toggled
1106         */
1107
1108        mWifiStateMachine.setDriverStart(true);
1109        mWifiStateMachine.reconnectCommand();
1110    }
1111
1112    /**
1113     * see {@link android.net.wifi.WifiManager#stopWifi}
1114     *
1115     */
1116    public void stopWifi() {
1117        enforceConnectivityInternalPermission();
1118        /*
1119         * TODO: if a stop is issued, wifi is brought up only by startWifi
1120         * unless wifi enabled status is toggled
1121         */
1122        mWifiStateMachine.setDriverStart(false);
1123    }
1124
1125    /**
1126     * see {@link android.net.wifi.WifiManager#addToBlacklist}
1127     *
1128     */
1129    public void addToBlacklist(String bssid) {
1130        enforceChangePermission();
1131
1132        mWifiStateMachine.addToBlacklist(bssid);
1133    }
1134
1135    /**
1136     * see {@link android.net.wifi.WifiManager#clearBlacklist}
1137     *
1138     */
1139    public void clearBlacklist() {
1140        enforceChangePermission();
1141
1142        mWifiStateMachine.clearBlacklist();
1143    }
1144
1145    /**
1146     * enable TDLS for the local NIC to remote NIC
1147     * The APPs don't know the remote MAC address to identify NIC though,
1148     * so we need to do additional work to find it from remote IP address
1149     */
1150
1151    class TdlsTaskParams {
1152        public String remoteIpAddress;
1153        public boolean enable;
1154    }
1155
1156    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1157        @Override
1158        protected Integer doInBackground(TdlsTaskParams... params) {
1159
1160            // Retrieve parameters for the call
1161            TdlsTaskParams param = params[0];
1162            String remoteIpAddress = param.remoteIpAddress.trim();
1163            boolean enable = param.enable;
1164
1165            // Get MAC address of Remote IP
1166            String macAddress = null;
1167
1168            BufferedReader reader = null;
1169
1170            try {
1171                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1172
1173                // Skip over the line bearing colum titles
1174                String line = reader.readLine();
1175
1176                while ((line = reader.readLine()) != null) {
1177                    String[] tokens = line.split("[ ]+");
1178                    if (tokens.length < 6) {
1179                        continue;
1180                    }
1181
1182                    // ARP column format is
1183                    // Address HWType HWAddress Flags Mask IFace
1184                    String ip = tokens[0];
1185                    String mac = tokens[3];
1186
1187                    if (remoteIpAddress.equals(ip)) {
1188                        macAddress = mac;
1189                        break;
1190                    }
1191                }
1192
1193                if (macAddress == null) {
1194                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1195                            "/proc/net/arp");
1196                } else {
1197                    enableTdlsWithMacAddress(macAddress, enable);
1198                }
1199
1200            } catch (FileNotFoundException e) {
1201                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1202            } catch (IOException e) {
1203                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1204            } finally {
1205                try {
1206                    if (reader != null) {
1207                        reader.close();
1208                    }
1209                }
1210                catch (IOException e) {
1211                    // Do nothing
1212                }
1213            }
1214
1215            return 0;
1216        }
1217    }
1218
1219    public void enableTdls(String remoteAddress, boolean enable) {
1220        if (remoteAddress == null) {
1221          throw new IllegalArgumentException("remoteAddress cannot be null");
1222        }
1223
1224        TdlsTaskParams params = new TdlsTaskParams();
1225        params.remoteIpAddress = remoteAddress;
1226        params.enable = enable;
1227        new TdlsTask().execute(params);
1228    }
1229
1230
1231    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1232        if (remoteMacAddress == null) {
1233          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1234        }
1235
1236        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1237    }
1238
1239    /**
1240     * Get a reference to handler. This is used by a client to establish
1241     * an AsyncChannel communication with WifiService
1242     */
1243    public Messenger getWifiServiceMessenger() {
1244        enforceAccessPermission();
1245        enforceChangePermission();
1246        return new Messenger(mClientHandler);
1247    }
1248
1249
1250    /**
1251     * Get the IP and proxy configuration file
1252     */
1253    public String getConfigFile() {
1254        enforceAccessPermission();
1255        return mWifiStateMachine.getConfigFile();
1256    }
1257
1258    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1259        @Override
1260        public void onReceive(Context context, Intent intent) {
1261            String action = intent.getAction();
1262            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1263                mWifiController.sendMessage(CMD_SCREEN_ON);
1264            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1265                mWifiController.sendMessage(CMD_USER_PRESENT);
1266            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1267                mWifiController.sendMessage(CMD_SCREEN_OFF);
1268            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1269                int pluggedType = intent.getIntExtra("plugged", 0);
1270                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1271            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1272                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1273                        BluetoothAdapter.STATE_DISCONNECTED);
1274                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1275            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1276                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1277                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1278            }
1279        }
1280    };
1281
1282    /**
1283     * Observes settings changes to scan always mode.
1284     */
1285    private void registerForScanModeChange() {
1286        ContentObserver contentObserver = new ContentObserver(null) {
1287            @Override
1288            public void onChange(boolean selfChange) {
1289                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1290                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1291            }
1292        };
1293
1294        mContext.getContentResolver().registerContentObserver(
1295                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1296                false, contentObserver);
1297    }
1298
1299    private void registerForBroadcasts() {
1300        IntentFilter intentFilter = new IntentFilter();
1301        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1302        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1303        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1304        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1305        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1306        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1307        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1308        mContext.registerReceiver(mReceiver, intentFilter);
1309    }
1310
1311    @Override
1312    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1313        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1314                != PackageManager.PERMISSION_GRANTED) {
1315            pw.println("Permission Denial: can't dump WifiService from from pid="
1316                    + Binder.getCallingPid()
1317                    + ", uid=" + Binder.getCallingUid());
1318            return;
1319        }
1320        pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1321        pw.println("Stay-awake conditions: " +
1322                Settings.Global.getInt(mContext.getContentResolver(),
1323                                       Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1324        pw.println("mMulticastEnabled " + mMulticastEnabled);
1325        pw.println("mMulticastDisabled " + mMulticastDisabled);
1326        mWifiController.dump(fd, pw, args);
1327        mSettingsStore.dump(fd, pw, args);
1328        mNotificationController.dump(fd, pw, args);
1329        mTrafficPoller.dump(fd, pw, args);
1330
1331        pw.println("Latest scan results:");
1332        List<ScanResult> scanResults = mWifiStateMachine.syncGetScanResultsList();
1333        if (scanResults != null && scanResults.size() != 0) {
1334            pw.println("  BSSID              Frequency   RSSI  Flags             SSID");
1335            for (ScanResult r : scanResults) {
1336                pw.printf("  %17s  %9d  %5d  %-16s  %s%n",
1337                                         r.BSSID,
1338                                         r.frequency,
1339                                         r.level,
1340                                         r.capabilities,
1341                                         r.SSID == null ? "" : r.SSID);
1342            }
1343        }
1344        pw.println();
1345        pw.println("Locks acquired: " + mFullLocksAcquired + " full, " +
1346                mFullHighPerfLocksAcquired + " full high perf, " +
1347                mScanLocksAcquired + " scan");
1348        pw.println("Locks released: " + mFullLocksReleased + " full, " +
1349                mFullHighPerfLocksReleased + " full high perf, " +
1350                mScanLocksReleased + " scan");
1351        pw.println();
1352        pw.println("Locks held:");
1353        mLocks.dump(pw);
1354
1355        mWifiWatchdogStateMachine.dump(fd, pw, args);
1356        pw.println();
1357        mWifiStateMachine.dump(fd, pw, args);
1358        pw.println();
1359    }
1360
1361    private class WifiLock extends DeathRecipient {
1362        WifiLock(int lockMode, String tag, IBinder binder, WorkSource ws) {
1363            super(lockMode, tag, binder, ws);
1364        }
1365
1366        public void binderDied() {
1367            synchronized (mLocks) {
1368                releaseWifiLockLocked(mBinder);
1369            }
1370        }
1371
1372        public String toString() {
1373            return "WifiLock{" + mTag + " type=" + mMode + " binder=" + mBinder + "}";
1374        }
1375    }
1376
1377    class LockList {
1378        private List<WifiLock> mList;
1379
1380        private LockList() {
1381            mList = new ArrayList<WifiLock>();
1382        }
1383
1384        synchronized boolean hasLocks() {
1385            return !mList.isEmpty();
1386        }
1387
1388        synchronized int getStrongestLockMode() {
1389            if (mList.isEmpty()) {
1390                return WifiManager.WIFI_MODE_FULL;
1391            }
1392
1393            if (mFullHighPerfLocksAcquired > mFullHighPerfLocksReleased) {
1394                return WifiManager.WIFI_MODE_FULL_HIGH_PERF;
1395            }
1396
1397            if (mFullLocksAcquired > mFullLocksReleased) {
1398                return WifiManager.WIFI_MODE_FULL;
1399            }
1400
1401            return WifiManager.WIFI_MODE_SCAN_ONLY;
1402        }
1403
1404        synchronized void updateWorkSource(WorkSource ws) {
1405            for (int i = 0; i < mLocks.mList.size(); i++) {
1406                ws.add(mLocks.mList.get(i).mWorkSource);
1407            }
1408        }
1409
1410        private void addLock(WifiLock lock) {
1411            if (findLockByBinder(lock.mBinder) < 0) {
1412                mList.add(lock);
1413            }
1414        }
1415
1416        private WifiLock removeLock(IBinder binder) {
1417            int index = findLockByBinder(binder);
1418            if (index >= 0) {
1419                WifiLock ret = mList.remove(index);
1420                ret.unlinkDeathRecipient();
1421                return ret;
1422            } else {
1423                return null;
1424            }
1425        }
1426
1427        private int findLockByBinder(IBinder binder) {
1428            int size = mList.size();
1429            for (int i = size - 1; i >= 0; i--) {
1430                if (mList.get(i).mBinder == binder)
1431                    return i;
1432            }
1433            return -1;
1434        }
1435
1436        private void dump(PrintWriter pw) {
1437            for (WifiLock l : mList) {
1438                pw.print("    ");
1439                pw.println(l);
1440            }
1441        }
1442    }
1443
1444    void enforceWakeSourcePermission(int uid, int pid) {
1445        if (uid == android.os.Process.myUid()) {
1446            return;
1447        }
1448        mContext.enforcePermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
1449                pid, uid, null);
1450    }
1451
1452    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1453        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1454        if (lockMode != WifiManager.WIFI_MODE_FULL &&
1455                lockMode != WifiManager.WIFI_MODE_SCAN_ONLY &&
1456                lockMode != WifiManager.WIFI_MODE_FULL_HIGH_PERF) {
1457            Slog.e(TAG, "Illegal argument, lockMode= " + lockMode);
1458            if (DBG) throw new IllegalArgumentException("lockMode=" + lockMode);
1459            return false;
1460        }
1461        if (ws != null && ws.size() == 0) {
1462            ws = null;
1463        }
1464        if (ws != null) {
1465            enforceWakeSourcePermission(Binder.getCallingUid(), Binder.getCallingPid());
1466        }
1467        if (ws == null) {
1468            ws = new WorkSource(Binder.getCallingUid());
1469        }
1470        WifiLock wifiLock = new WifiLock(lockMode, tag, binder, ws);
1471        synchronized (mLocks) {
1472            return acquireWifiLockLocked(wifiLock);
1473        }
1474    }
1475
1476    private void noteAcquireWifiLock(WifiLock wifiLock) throws RemoteException {
1477        switch(wifiLock.mMode) {
1478            case WifiManager.WIFI_MODE_FULL:
1479            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1480            case WifiManager.WIFI_MODE_SCAN_ONLY:
1481                mBatteryStats.noteFullWifiLockAcquiredFromSource(wifiLock.mWorkSource);
1482                break;
1483        }
1484    }
1485
1486    private void noteReleaseWifiLock(WifiLock wifiLock) throws RemoteException {
1487        switch(wifiLock.mMode) {
1488            case WifiManager.WIFI_MODE_FULL:
1489            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1490            case WifiManager.WIFI_MODE_SCAN_ONLY:
1491                mBatteryStats.noteFullWifiLockReleasedFromSource(wifiLock.mWorkSource);
1492                break;
1493        }
1494    }
1495
1496    private boolean acquireWifiLockLocked(WifiLock wifiLock) {
1497        if (DBG) Slog.d(TAG, "acquireWifiLockLocked: " + wifiLock);
1498
1499        mLocks.addLock(wifiLock);
1500
1501        long ident = Binder.clearCallingIdentity();
1502        try {
1503            noteAcquireWifiLock(wifiLock);
1504            switch(wifiLock.mMode) {
1505            case WifiManager.WIFI_MODE_FULL:
1506                ++mFullLocksAcquired;
1507                break;
1508            case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1509                ++mFullHighPerfLocksAcquired;
1510                break;
1511
1512            case WifiManager.WIFI_MODE_SCAN_ONLY:
1513                ++mScanLocksAcquired;
1514                break;
1515            }
1516            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1517            return true;
1518        } catch (RemoteException e) {
1519            return false;
1520        } finally {
1521            Binder.restoreCallingIdentity(ident);
1522        }
1523    }
1524
1525    public void updateWifiLockWorkSource(IBinder lock, WorkSource ws) {
1526        int uid = Binder.getCallingUid();
1527        int pid = Binder.getCallingPid();
1528        if (ws != null && ws.size() == 0) {
1529            ws = null;
1530        }
1531        if (ws != null) {
1532            enforceWakeSourcePermission(uid, pid);
1533        }
1534        long ident = Binder.clearCallingIdentity();
1535        try {
1536            synchronized (mLocks) {
1537                int index = mLocks.findLockByBinder(lock);
1538                if (index < 0) {
1539                    throw new IllegalArgumentException("Wifi lock not active");
1540                }
1541                WifiLock wl = mLocks.mList.get(index);
1542                noteReleaseWifiLock(wl);
1543                wl.mWorkSource = ws != null ? new WorkSource(ws) : new WorkSource(uid);
1544                noteAcquireWifiLock(wl);
1545            }
1546        } catch (RemoteException e) {
1547        } finally {
1548            Binder.restoreCallingIdentity(ident);
1549        }
1550    }
1551
1552    public boolean releaseWifiLock(IBinder lock) {
1553        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
1554        synchronized (mLocks) {
1555            return releaseWifiLockLocked(lock);
1556        }
1557    }
1558
1559    private boolean releaseWifiLockLocked(IBinder lock) {
1560        boolean hadLock;
1561
1562        WifiLock wifiLock = mLocks.removeLock(lock);
1563
1564        if (DBG) Slog.d(TAG, "releaseWifiLockLocked: " + wifiLock);
1565
1566        hadLock = (wifiLock != null);
1567
1568        long ident = Binder.clearCallingIdentity();
1569        try {
1570            if (hadLock) {
1571                noteReleaseWifiLock(wifiLock);
1572                switch(wifiLock.mMode) {
1573                    case WifiManager.WIFI_MODE_FULL:
1574                        ++mFullLocksReleased;
1575                        break;
1576                    case WifiManager.WIFI_MODE_FULL_HIGH_PERF:
1577                        ++mFullHighPerfLocksReleased;
1578                        break;
1579                    case WifiManager.WIFI_MODE_SCAN_ONLY:
1580                        ++mScanLocksReleased;
1581                        break;
1582                }
1583                mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1584            }
1585        } catch (RemoteException e) {
1586        } finally {
1587            Binder.restoreCallingIdentity(ident);
1588        }
1589
1590        return hadLock;
1591    }
1592
1593    private abstract class DeathRecipient
1594            implements IBinder.DeathRecipient {
1595        String mTag;
1596        int mMode;
1597        IBinder mBinder;
1598        WorkSource mWorkSource;
1599
1600        DeathRecipient(int mode, String tag, IBinder binder, WorkSource ws) {
1601            super();
1602            mTag = tag;
1603            mMode = mode;
1604            mBinder = binder;
1605            mWorkSource = ws;
1606            try {
1607                mBinder.linkToDeath(this, 0);
1608            } catch (RemoteException e) {
1609                binderDied();
1610            }
1611        }
1612
1613        void unlinkDeathRecipient() {
1614            mBinder.unlinkToDeath(this, 0);
1615        }
1616    }
1617
1618    private class Multicaster extends DeathRecipient {
1619        Multicaster(String tag, IBinder binder) {
1620            super(Binder.getCallingUid(), tag, binder, null);
1621        }
1622
1623        public void binderDied() {
1624            Slog.e(TAG, "Multicaster binderDied");
1625            synchronized (mMulticasters) {
1626                int i = mMulticasters.indexOf(this);
1627                if (i != -1) {
1628                    removeMulticasterLocked(i, mMode);
1629                }
1630            }
1631        }
1632
1633        public String toString() {
1634            return "Multicaster{" + mTag + " binder=" + mBinder + "}";
1635        }
1636
1637        public int getUid() {
1638            return mMode;
1639        }
1640    }
1641
1642    public void initializeMulticastFiltering() {
1643        enforceMulticastChangePermission();
1644
1645        synchronized (mMulticasters) {
1646            // if anybody had requested filters be off, leave off
1647            if (mMulticasters.size() != 0) {
1648                return;
1649            } else {
1650                mWifiStateMachine.startFilteringMulticastV4Packets();
1651            }
1652        }
1653    }
1654
1655    public void acquireMulticastLock(IBinder binder, String tag) {
1656        enforceMulticastChangePermission();
1657
1658        synchronized (mMulticasters) {
1659            mMulticastEnabled++;
1660            mMulticasters.add(new Multicaster(tag, binder));
1661            // Note that we could call stopFilteringMulticastV4Packets only when
1662            // our new size == 1 (first call), but this function won't
1663            // be called often and by making the stopPacket call each
1664            // time we're less fragile and self-healing.
1665            mWifiStateMachine.stopFilteringMulticastV4Packets();
1666        }
1667
1668        int uid = Binder.getCallingUid();
1669        final long ident = Binder.clearCallingIdentity();
1670        try {
1671            mBatteryStats.noteWifiMulticastEnabled(uid);
1672        } catch (RemoteException e) {
1673        } finally {
1674            Binder.restoreCallingIdentity(ident);
1675        }
1676    }
1677
1678    public void releaseMulticastLock() {
1679        enforceMulticastChangePermission();
1680
1681        int uid = Binder.getCallingUid();
1682        synchronized (mMulticasters) {
1683            mMulticastDisabled++;
1684            int size = mMulticasters.size();
1685            for (int i = size - 1; i >= 0; i--) {
1686                Multicaster m = mMulticasters.get(i);
1687                if ((m != null) && (m.getUid() == uid)) {
1688                    removeMulticasterLocked(i, uid);
1689                }
1690            }
1691        }
1692    }
1693
1694    private void removeMulticasterLocked(int i, int uid)
1695    {
1696        Multicaster removed = mMulticasters.remove(i);
1697
1698        if (removed != null) {
1699            removed.unlinkDeathRecipient();
1700        }
1701        if (mMulticasters.size() == 0) {
1702            mWifiStateMachine.startFilteringMulticastV4Packets();
1703        }
1704
1705        final long ident = Binder.clearCallingIdentity();
1706        try {
1707            mBatteryStats.noteWifiMulticastDisabled(uid);
1708        } catch (RemoteException e) {
1709        } finally {
1710            Binder.restoreCallingIdentity(ident);
1711        }
1712    }
1713
1714    public boolean isMulticastEnabled() {
1715        enforceAccessPermission();
1716
1717        synchronized (mMulticasters) {
1718            return (mMulticasters.size() > 0);
1719        }
1720    }
1721
1722    public WifiMonitor getWifiMonitor() {
1723        return mWifiStateMachine.getWifiMonitor();
1724    }
1725
1726
1727    public void enableVerboseLogging(int verbose) {
1728        enforceAccessPermission();
1729        mWifiStateMachine.enableVerboseLogging(verbose);
1730    }
1731
1732    public int getVerboseLoggingLevel() {
1733        enforceAccessPermission();
1734        return mWifiStateMachine.getVerboseLoggingLevel();
1735    }
1736
1737    public void enableAggressiveHandover(int enabled) {
1738        enforceAccessPermission();
1739        mWifiStateMachine.enableAggressiveHandover(enabled);
1740    }
1741
1742    public int getAggressiveHandover() {
1743        enforceAccessPermission();
1744        return mWifiStateMachine.getAggressiveHandover();
1745    }
1746
1747    public void setAllowScansWithTraffic(int enabled) {
1748        enforceAccessPermission();
1749        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1750    }
1751
1752    public int getAllowScansWithTraffic() {
1753        enforceAccessPermission();
1754        return mWifiStateMachine.getAllowScansWithTraffic();
1755    }
1756
1757    /* Return the Wifi Connection statistics object */
1758    public WifiConnectionStatistics getConnectionStatistics() {
1759        enforceAccessPermission();
1760        enforceReadCredentialPermission();
1761        if (mWifiStateMachineChannel != null) {
1762            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1763        } else {
1764            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1765            return null;
1766        }
1767    }
1768}
1769