WifiServiceImpl.java revision 84ee4726383fd968ab43caf120d15d9f47a51a54
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi;
18
19import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
20import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
21import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
22import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
23import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
24import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
25import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
26import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
27import static com.android.server.wifi.WifiController.CMD_SET_AP;
28import static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
29import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
30
31import android.Manifest;
32import android.app.AppOpsManager;
33import android.bluetooth.BluetoothAdapter;
34import android.content.BroadcastReceiver;
35import android.content.Context;
36import android.content.Intent;
37import android.content.IntentFilter;
38import android.content.pm.PackageManager;
39import android.database.ContentObserver;
40import android.net.ConnectivityManager;
41import android.net.DhcpInfo;
42import android.net.DhcpResults;
43import android.net.Network;
44import android.net.NetworkUtils;
45import android.net.Uri;
46import android.net.ip.IpManager;
47import android.net.wifi.IWifiManager;
48import android.net.wifi.PasspointManagementObjectDefinition;
49import android.net.wifi.ScanResult;
50import android.net.wifi.ScanSettings;
51import android.net.wifi.WifiActivityEnergyInfo;
52import android.net.wifi.WifiConfiguration;
53import android.net.wifi.WifiConnectionStatistics;
54import android.net.wifi.WifiEnterpriseConfig;
55import android.net.wifi.WifiInfo;
56import android.net.wifi.WifiLinkLayerStats;
57import android.net.wifi.WifiManager;
58import android.net.wifi.WifiScanner;
59import android.os.AsyncTask;
60import android.os.BatteryStats;
61import android.os.Binder;
62import android.os.Build;
63import android.os.Bundle;
64import android.os.Handler;
65import android.os.HandlerThread;
66import android.os.IBinder;
67import android.os.Looper;
68import android.os.Message;
69import android.os.Messenger;
70import android.os.PowerManager;
71import android.os.RemoteException;
72import android.os.ResultReceiver;
73import android.os.SystemClock;
74import android.os.UserHandle;
75import android.os.UserManager;
76import android.os.WorkSource;
77import android.provider.Settings;
78import android.text.TextUtils;
79import android.util.Log;
80import android.util.Slog;
81
82import com.android.internal.telephony.IccCardConstants;
83import com.android.internal.telephony.PhoneConstants;
84import com.android.internal.telephony.TelephonyIntents;
85import com.android.internal.util.AsyncChannel;
86import com.android.server.wifi.configparse.ConfigBuilder;
87import com.android.server.wifi.util.WifiPermissionsUtil;
88
89import org.xml.sax.SAXException;
90
91import java.io.BufferedReader;
92import java.io.FileDescriptor;
93import java.io.FileNotFoundException;
94import java.io.FileReader;
95import java.io.IOException;
96import java.io.PrintWriter;
97import java.net.Inet4Address;
98import java.net.InetAddress;
99import java.security.GeneralSecurityException;
100import java.security.KeyStore;
101import java.security.cert.CertPath;
102import java.security.cert.CertPathValidator;
103import java.security.cert.CertPathValidatorException;
104import java.security.cert.CertificateFactory;
105import java.security.cert.PKIXParameters;
106import java.security.cert.X509Certificate;
107import java.util.ArrayList;
108import java.util.Arrays;
109import java.util.List;
110
111/**
112 * WifiService handles remote WiFi operation requests by implementing
113 * the IWifiManager interface.
114 *
115 * @hide
116 */
117public class WifiServiceImpl extends IWifiManager.Stub {
118    private static final String TAG = "WifiService";
119    private static final boolean DBG = true;
120    private static final boolean VDBG = false;
121
122    // Dumpsys argument to enable/disable disconnect on IP reachability failures.
123    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT = "set-ipreach-disconnect";
124    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED = "enabled";
125    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED = "disabled";
126
127    final WifiStateMachine mWifiStateMachine;
128
129    private final Context mContext;
130    private final FrameworkFacade mFacade;
131
132    private final PowerManager mPowerManager;
133    private final AppOpsManager mAppOps;
134    private final UserManager mUserManager;
135    private final WifiCountryCode mCountryCode;
136    // Debug counter tracking scan requests sent by WifiManager
137    private int scanRequestCounter = 0;
138
139    /* Tracks the open wi-fi network notification */
140    private WifiNotificationController mNotificationController;
141    /* Polls traffic stats and notifies clients */
142    private WifiTrafficPoller mTrafficPoller;
143    /* Tracks the persisted states for wi-fi & airplane mode */
144    final WifiSettingsStore mSettingsStore;
145    /* Logs connection events and some general router and scan stats */
146    private final WifiMetrics mWifiMetrics;
147    /* Manages affiliated certificates for current user */
148    private final WifiCertManager mCertManager;
149
150    private final WifiInjector mWifiInjector;
151    /* Backup/Restore Module */
152    private final WifiBackupRestore mWifiBackupRestore;
153
154    private WifiScanner mWifiScanner;
155
156    /**
157     * Asynchronous channel to WifiStateMachine
158     */
159    private AsyncChannel mWifiStateMachineChannel;
160
161    private WifiPermissionsUtil mWifiPermissionsUtil;
162
163    /**
164     * Handles client connections
165     */
166    private class ClientHandler extends Handler {
167
168        ClientHandler(Looper looper) {
169            super(looper);
170        }
171
172        @Override
173        public void handleMessage(Message msg) {
174            switch (msg.what) {
175                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
176                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
177                        if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
178                        // We track the clients by the Messenger
179                        // since it is expected to be always available
180                        mTrafficPoller.addClient(msg.replyTo);
181                    } else {
182                        Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
183                    }
184                    break;
185                }
186                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
187                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
188                        if (DBG) Slog.d(TAG, "Send failed, client connection lost");
189                    } else {
190                        if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
191                    }
192                    mTrafficPoller.removeClient(msg.replyTo);
193                    break;
194                }
195                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
196                    AsyncChannel ac = new AsyncChannel();
197                    ac.connect(mContext, this, msg.replyTo);
198                    break;
199                }
200                /* Client commands are forwarded to state machine */
201                case WifiManager.CONNECT_NETWORK:
202                case WifiManager.SAVE_NETWORK: {
203                    WifiConfiguration config = (WifiConfiguration) msg.obj;
204                    int networkId = msg.arg1;
205                    if (msg.what == WifiManager.SAVE_NETWORK) {
206                        Slog.d("WiFiServiceImpl ", "SAVE"
207                                + " nid=" + Integer.toString(networkId)
208                                + " uid=" + msg.sendingUid
209                                + " name="
210                                + mContext.getPackageManager().getNameForUid(msg.sendingUid));
211                    }
212                    if (msg.what == WifiManager.CONNECT_NETWORK) {
213                        Slog.d("WiFiServiceImpl ", "CONNECT "
214                                + " nid=" + Integer.toString(networkId)
215                                + " uid=" + msg.sendingUid
216                                + " name="
217                                + mContext.getPackageManager().getNameForUid(msg.sendingUid));
218                    }
219
220                    if (config != null && isValid(config)) {
221                        if (DBG) Slog.d(TAG, "Connect with config" + config);
222                        mWifiStateMachine.sendMessage(Message.obtain(msg));
223                    } else if (config == null
224                            && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
225                        if (DBG) Slog.d(TAG, "Connect with networkId" + networkId);
226                        mWifiStateMachine.sendMessage(Message.obtain(msg));
227                    } else {
228                        Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
229                        if (msg.what == WifiManager.CONNECT_NETWORK) {
230                            replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
231                                    WifiManager.INVALID_ARGS);
232                        } else {
233                            replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
234                                    WifiManager.INVALID_ARGS);
235                        }
236                    }
237                    break;
238                }
239                case WifiManager.FORGET_NETWORK:
240                    mWifiStateMachine.sendMessage(Message.obtain(msg));
241                    break;
242                case WifiManager.START_WPS:
243                case WifiManager.CANCEL_WPS:
244                case WifiManager.DISABLE_NETWORK:
245                case WifiManager.RSSI_PKTCNT_FETCH: {
246                    mWifiStateMachine.sendMessage(Message.obtain(msg));
247                    break;
248                }
249                default: {
250                    Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
251                    break;
252                }
253            }
254        }
255
256        private void replyFailed(Message msg, int what, int why) {
257            Message reply = Message.obtain();
258            reply.what = what;
259            reply.arg1 = why;
260            try {
261                msg.replyTo.send(reply);
262            } catch (RemoteException e) {
263                // There's not much we can do if reply can't be sent!
264            }
265        }
266    }
267    private ClientHandler mClientHandler;
268
269    /**
270     * Handles interaction with WifiStateMachine
271     */
272    private class WifiStateMachineHandler extends Handler {
273        private AsyncChannel mWsmChannel;
274
275        WifiStateMachineHandler(Looper looper) {
276            super(looper);
277            mWsmChannel = new AsyncChannel();
278            mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
279        }
280
281        @Override
282        public void handleMessage(Message msg) {
283            switch (msg.what) {
284                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
285                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
286                        mWifiStateMachineChannel = mWsmChannel;
287                    } else {
288                        Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
289                        mWifiStateMachineChannel = null;
290                    }
291                    break;
292                }
293                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
294                    Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
295                    mWifiStateMachineChannel = null;
296                    //Re-establish connection to state machine
297                    mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
298                    break;
299                }
300                default: {
301                    Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
302                    break;
303                }
304            }
305        }
306    }
307
308    WifiStateMachineHandler mWifiStateMachineHandler;
309    private WifiController mWifiController;
310    private final WifiLockManager mWifiLockManager;
311    private final WifiMulticastLockManager mWifiMulticastLockManager;
312
313    public WifiServiceImpl(Context context) {
314        mContext = context;
315        mWifiInjector = new WifiInjector(context);
316
317        mFacade = mWifiInjector.getFrameworkFacade();
318        mWifiMetrics = mWifiInjector.getWifiMetrics();
319        mTrafficPoller = mWifiInjector.getWifiTrafficPoller();
320        mUserManager = UserManager.get(mContext);
321        mCountryCode = mWifiInjector.getWifiCountryCode();
322        mWifiStateMachine = mWifiInjector.getWifiStateMachine();
323        mWifiStateMachine.enableRssiPolling(true);
324        mSettingsStore = mWifiInjector.getWifiSettingsStore();
325        mPowerManager = mContext.getSystemService(PowerManager.class);
326        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
327        mCertManager = mWifiInjector.getWifiCertManager();
328
329        mNotificationController = mWifiInjector.getWifiNotificationController();
330
331        mWifiLockManager = mWifiInjector.getWifiLockManager();
332        mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
333        HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
334        mClientHandler = new ClientHandler(wifiServiceHandlerThread.getLooper());
335        mWifiStateMachineHandler =
336                new WifiStateMachineHandler(wifiServiceHandlerThread.getLooper());
337        mWifiController = mWifiInjector.getWifiController();
338        mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
339        mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
340        enableVerboseLoggingInternal(getVerboseLoggingLevel());
341    }
342
343
344    /**
345     * Check if Wi-Fi needs to be enabled and start
346     * if needed
347     *
348     * This function is used only at boot time
349     */
350    public void checkAndStartWifi() {
351        /* Check if wi-fi needs to be enabled */
352        boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
353        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
354                (wifiEnabled ? "enabled" : "disabled"));
355
356        registerForScanModeChange();
357        mContext.registerReceiver(
358                new BroadcastReceiver() {
359                    @Override
360                    public void onReceive(Context context, Intent intent) {
361                        if (mSettingsStore.handleAirplaneModeToggled()) {
362                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
363                        }
364                        if (mSettingsStore.isAirplaneModeOn()) {
365                            Log.d(TAG, "resetting country code because Airplane mode is ON");
366                            mCountryCode.airplaneModeEnabled();
367                        }
368                    }
369                },
370                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
371
372        mContext.registerReceiver(
373                new BroadcastReceiver() {
374                    @Override
375                    public void onReceive(Context context, Intent intent) {
376                        String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
377                        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
378                            Log.d(TAG, "resetting networks because SIM was removed");
379                            mWifiStateMachine.resetSimAuthNetworks(false);
380                            Log.d(TAG, "resetting country code because SIM is removed");
381                            mCountryCode.simCardRemoved();
382                        } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
383                            Log.d(TAG, "resetting networks because SIM was loaded");
384                            mWifiStateMachine.resetSimAuthNetworks(true);
385                        }
386                    }
387                },
388                new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
389
390        // Adding optimizations of only receiving broadcasts when wifi is enabled
391        // can result in race conditions when apps toggle wifi in the background
392        // without active user involvement. Always receive broadcasts.
393        registerForBroadcasts();
394        registerForPackageOrUserRemoval();
395        mInIdleMode = mPowerManager.isDeviceIdleMode();
396
397        mWifiController.start();
398
399        // If we are already disabled (could be due to airplane mode), avoid changing persist
400        // state here
401        if (wifiEnabled) setWifiEnabled(wifiEnabled);
402    }
403
404    public void handleUserSwitch(int userId) {
405        mWifiStateMachine.handleUserSwitch(userId);
406    }
407
408    public void handleUserUnlock(int userId) {
409        mWifiStateMachine.handleUserUnlock(userId);
410    }
411
412    public void handleUserStop(int userId) {
413        mWifiStateMachine.handleUserStop(userId);
414    }
415
416    /**
417     * see {@link android.net.wifi.WifiManager#pingSupplicant()}
418     * @return {@code true} if the operation succeeds, {@code false} otherwise
419     */
420    @Override
421    public boolean pingSupplicant() {
422        enforceAccessPermission();
423        if (mWifiStateMachineChannel != null) {
424            return mWifiStateMachine.syncPingSupplicant(mWifiStateMachineChannel);
425        } else {
426            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
427            return false;
428        }
429    }
430
431    /**
432     * see {@link android.net.wifi.WifiManager#startScan}
433     * and {@link android.net.wifi.WifiManager#startCustomizedScan}
434     *
435     * @param settings If null, use default parameter, i.e. full scan.
436     * @param workSource If null, all blame is given to the calling uid.
437     */
438    @Override
439    public void startScan(ScanSettings settings, WorkSource workSource) {
440        enforceChangePermission();
441        synchronized (this) {
442            if (mWifiScanner == null) {
443                mWifiScanner = mWifiInjector.getWifiScanner();
444            }
445            if (mInIdleMode) {
446                // Need to send an immediate scan result broadcast in case the
447                // caller is waiting for a result ..
448
449                // clear calling identity to send broadcast
450                long callingIdentity = Binder.clearCallingIdentity();
451                try {
452                    // TODO: investigate if the logic to cancel scans when idle can move to
453                    // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
454                    // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
455                    // be sent directly until b/31398592 is fixed.
456                    Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
457                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
458                    intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
459                    mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
460                } finally {
461                    // restore calling identity
462                    Binder.restoreCallingIdentity(callingIdentity);
463                }
464                mScanPending = true;
465                return;
466            }
467        }
468        if (settings != null) {
469            settings = new ScanSettings(settings);
470            if (!settings.isValid()) {
471                Slog.e(TAG, "invalid scan setting");
472                return;
473            }
474        }
475        if (workSource != null) {
476            enforceWorkSourcePermission();
477            // WifiManager currently doesn't use names, so need to clear names out of the
478            // supplied WorkSource to allow future WorkSource combining.
479            workSource.clearNames();
480        }
481        if (workSource == null && Binder.getCallingUid() >= 0) {
482            workSource = new WorkSource(Binder.getCallingUid());
483        }
484        mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
485                settings, workSource);
486    }
487
488    @Override
489    public String getWpsNfcConfigurationToken(int netId) {
490        enforceConnectivityInternalPermission();
491        return mWifiStateMachine.syncGetWpsNfcConfigurationToken(netId);
492    }
493
494    boolean mInIdleMode;
495    boolean mScanPending;
496
497    void handleIdleModeChanged() {
498        boolean doScan = false;
499        synchronized (this) {
500            boolean idle = mPowerManager.isDeviceIdleMode();
501            if (mInIdleMode != idle) {
502                mInIdleMode = idle;
503                if (!idle) {
504                    if (mScanPending) {
505                        mScanPending = false;
506                        doScan = true;
507                    }
508                }
509            }
510        }
511        if (doScan) {
512            // Someone requested a scan while we were idle; do a full scan now.
513            startScan(null, null);
514        }
515    }
516
517    private void enforceAccessPermission() {
518        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
519                "WifiService");
520    }
521
522    private void enforceChangePermission() {
523        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
524                "WifiService");
525    }
526
527    private void enforceLocationHardwarePermission() {
528        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE,
529                "LocationHardware");
530    }
531
532    private void enforceReadCredentialPermission() {
533        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
534                                                "WifiService");
535    }
536
537    private void enforceWorkSourcePermission() {
538        mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
539                "WifiService");
540
541    }
542
543    private void enforceMulticastChangePermission() {
544        mContext.enforceCallingOrSelfPermission(
545                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
546                "WifiService");
547    }
548
549    private void enforceConnectivityInternalPermission() {
550        mContext.enforceCallingOrSelfPermission(
551                android.Manifest.permission.CONNECTIVITY_INTERNAL,
552                "ConnectivityService");
553    }
554
555    /**
556     * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
557     * @param enable {@code true} to enable, {@code false} to disable.
558     * @return {@code true} if the enable/disable operation was
559     *         started or is already in the queue.
560     */
561    @Override
562    public synchronized boolean setWifiEnabled(boolean enable) {
563        enforceChangePermission();
564        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
565                    + ", uid=" + Binder.getCallingUid());
566
567        /*
568        * Caller might not have WRITE_SECURE_SETTINGS,
569        * only CHANGE_WIFI_STATE is enforced
570        */
571
572        long ident = Binder.clearCallingIdentity();
573        try {
574            if (! mSettingsStore.handleWifiToggled(enable)) {
575                // Nothing to do if wifi cannot be toggled
576                return true;
577            }
578        } finally {
579            Binder.restoreCallingIdentity(ident);
580        }
581
582        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
583        return true;
584    }
585
586    /**
587     * see {@link WifiManager#getWifiState()}
588     * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
589     *         {@link WifiManager#WIFI_STATE_DISABLING},
590     *         {@link WifiManager#WIFI_STATE_ENABLED},
591     *         {@link WifiManager#WIFI_STATE_ENABLING},
592     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
593     */
594    @Override
595    public int getWifiEnabledState() {
596        enforceAccessPermission();
597        return mWifiStateMachine.syncGetWifiState();
598    }
599
600    /**
601     * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
602     * @param wifiConfig SSID, security and channel details as
603     *        part of WifiConfiguration
604     * @param enabled true to enable and false to disable
605     */
606    @Override
607    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
608        enforceChangePermission();
609        ConnectivityManager.enforceTetherChangePermission(mContext);
610        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
611            throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
612        }
613        // null wifiConfig is a meaningful input for CMD_SET_AP
614        if (wifiConfig == null || isValid(wifiConfig)) {
615            mWifiController.obtainMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig).sendToTarget();
616        } else {
617            Slog.e(TAG, "Invalid WifiConfiguration");
618        }
619    }
620
621    /**
622     * see {@link WifiManager#getWifiApState()}
623     * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
624     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
625     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
626     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
627     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
628     */
629    @Override
630    public int getWifiApEnabledState() {
631        enforceAccessPermission();
632        return mWifiStateMachine.syncGetWifiApState();
633    }
634
635    /**
636     * see {@link WifiManager#getWifiApConfiguration()}
637     * @return soft access point configuration
638     */
639    @Override
640    public WifiConfiguration getWifiApConfiguration() {
641        enforceAccessPermission();
642        return mWifiStateMachine.syncGetWifiApConfiguration();
643    }
644
645    /**
646     * see {@link WifiManager#buildWifiConfig()}
647     * @return a WifiConfiguration.
648     */
649    @Override
650    public WifiConfiguration buildWifiConfig(String uriString, String mimeType, byte[] data) {
651        if (mimeType.equals(ConfigBuilder.WifiConfigType)) {
652            try {
653                return ConfigBuilder.buildConfig(uriString, data, mContext);
654            }
655            catch (IOException | GeneralSecurityException | SAXException e) {
656                Log.e(TAG, "Failed to parse wi-fi configuration: " + e);
657            }
658        }
659        else {
660            Log.i(TAG, "Unknown wi-fi config type: " + mimeType);
661        }
662        return null;
663    }
664
665    /**
666     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
667     * @param wifiConfig WifiConfiguration details for soft access point
668     */
669    @Override
670    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
671        enforceChangePermission();
672        if (wifiConfig == null)
673            return;
674        if (isValid(wifiConfig)) {
675            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
676        } else {
677            Slog.e(TAG, "Invalid WifiConfiguration");
678        }
679    }
680
681    /**
682     * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
683     */
684    @Override
685    public boolean isScanAlwaysAvailable() {
686        enforceAccessPermission();
687        return mSettingsStore.isScanAlwaysAvailable();
688    }
689
690    /**
691     * see {@link android.net.wifi.WifiManager#disconnect()}
692     */
693    @Override
694    public void disconnect() {
695        enforceChangePermission();
696        mWifiStateMachine.disconnectCommand();
697    }
698
699    /**
700     * see {@link android.net.wifi.WifiManager#reconnect()}
701     */
702    @Override
703    public void reconnect() {
704        enforceChangePermission();
705        mWifiStateMachine.reconnectCommand();
706    }
707
708    /**
709     * see {@link android.net.wifi.WifiManager#reassociate()}
710     */
711    @Override
712    public void reassociate() {
713        enforceChangePermission();
714        mWifiStateMachine.reassociateCommand();
715    }
716
717    /**
718     * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
719     */
720    @Override
721    public int getSupportedFeatures() {
722        enforceAccessPermission();
723        if (mWifiStateMachineChannel != null) {
724            return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
725        } else {
726            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
727            return 0;
728        }
729    }
730
731    @Override
732    public void requestActivityInfo(ResultReceiver result) {
733        Bundle bundle = new Bundle();
734        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
735        result.send(0, bundle);
736    }
737
738    /**
739     * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
740     */
741    @Override
742    public WifiActivityEnergyInfo reportActivityInfo() {
743        enforceAccessPermission();
744        if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
745            return null;
746        }
747        WifiLinkLayerStats stats;
748        WifiActivityEnergyInfo energyInfo = null;
749        if (mWifiStateMachineChannel != null) {
750            stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
751            if (stats != null) {
752                final long rxIdleCurrent = mContext.getResources().getInteger(
753                        com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
754                final long rxCurrent = mContext.getResources().getInteger(
755                        com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
756                final long txCurrent = mContext.getResources().getInteger(
757                        com.android.internal.R.integer.config_wifi_tx_cur_ma);
758                final double voltage = mContext.getResources().getInteger(
759                        com.android.internal.R.integer.config_wifi_operating_voltage_mv)
760                        / 1000.0;
761
762                final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
763                final long[] txTimePerLevel;
764                if (stats.tx_time_per_level != null) {
765                    txTimePerLevel = new long[stats.tx_time_per_level.length];
766                    for (int i = 0; i < txTimePerLevel.length; i++) {
767                        txTimePerLevel[i] = stats.tx_time_per_level[i];
768                        // TODO(b/27227497): Need to read the power consumed per level from config
769                    }
770                } else {
771                    // This will happen if the HAL get link layer API returned null.
772                    txTimePerLevel = new long[0];
773                }
774                final long energyUsed = (long)((stats.tx_time * txCurrent +
775                        stats.rx_time * rxCurrent +
776                        rxIdleTime * rxIdleCurrent) * voltage);
777                if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
778                        stats.rx_time < 0 || energyUsed < 0) {
779                    StringBuilder sb = new StringBuilder();
780                    sb.append(" rxIdleCur=" + rxIdleCurrent);
781                    sb.append(" rxCur=" + rxCurrent);
782                    sb.append(" txCur=" + txCurrent);
783                    sb.append(" voltage=" + voltage);
784                    sb.append(" on_time=" + stats.on_time);
785                    sb.append(" tx_time=" + stats.tx_time);
786                    sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
787                    sb.append(" rx_time=" + stats.rx_time);
788                    sb.append(" rxIdleTime=" + rxIdleTime);
789                    sb.append(" energy=" + energyUsed);
790                    Log.d(TAG, " reportActivityInfo: " + sb.toString());
791                }
792
793                // Convert the LinkLayerStats into EnergyActivity
794                energyInfo = new WifiActivityEnergyInfo(SystemClock.elapsedRealtime(),
795                        WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
796                        txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed);
797            }
798            if (energyInfo != null && energyInfo.isValid()) {
799                return energyInfo;
800            } else {
801                return null;
802            }
803        } else {
804            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
805            return null;
806        }
807    }
808
809    /**
810     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
811     * @return the list of configured networks
812     */
813    @Override
814    public List<WifiConfiguration> getConfiguredNetworks() {
815        enforceAccessPermission();
816        if (mWifiStateMachineChannel != null) {
817            return mWifiStateMachine.syncGetConfiguredNetworks(Binder.getCallingUid(),
818                    mWifiStateMachineChannel);
819        } else {
820            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
821            return null;
822        }
823    }
824
825    /**
826     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
827     * @return the list of configured networks with real preSharedKey
828     */
829    @Override
830    public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
831        enforceReadCredentialPermission();
832        enforceAccessPermission();
833        if (mWifiStateMachineChannel != null) {
834            return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
835        } else {
836            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
837            return null;
838        }
839    }
840
841    /**
842     * Returns a WifiConfiguration matching this ScanResult
843     * @param scanResult scanResult that represents the BSSID
844     * @return {@link WifiConfiguration} that matches this BSSID or null
845     */
846    @Override
847    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
848        enforceAccessPermission();
849        return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
850    }
851
852    /**
853     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
854     * @return the supplicant-assigned identifier for the new or updated
855     * network if the operation succeeds, or {@code -1} if it fails
856     */
857    @Override
858    public int addOrUpdateNetwork(WifiConfiguration config) {
859        enforceChangePermission();
860        if (isValid(config) && isValidPasspoint(config)) {
861
862            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
863
864            if (config.isPasspoint() &&
865                    (enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
866                            enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS)) {
867                if (config.updateIdentifier != null) {
868                    enforceAccessPermission();
869                }
870                else {
871                    try {
872                        verifyCert(enterpriseConfig.getCaCertificate());
873                    } catch (CertPathValidatorException cpve) {
874                        Slog.e(TAG, "CA Cert " +
875                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
876                                " untrusted: " + cpve.getMessage());
877                        return -1;
878                    } catch (GeneralSecurityException | IOException e) {
879                        Slog.e(TAG, "Failed to verify certificate" +
880                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
881                                ": " + e);
882                        return -1;
883                    }
884                }
885            }
886
887            //TODO: pass the Uid the WifiStateMachine as a message parameter
888            Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
889                    + " SSID " + config.SSID
890                    + " nid=" + Integer.toString(config.networkId));
891            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
892                config.creatorUid = Binder.getCallingUid();
893            } else {
894                config.lastUpdateUid = Binder.getCallingUid();
895            }
896            if (mWifiStateMachineChannel != null) {
897                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
898            } else {
899                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
900                return -1;
901            }
902        } else {
903            Slog.e(TAG, "bad network configuration");
904            return -1;
905        }
906    }
907
908    public static void verifyCert(X509Certificate caCert)
909            throws GeneralSecurityException, IOException {
910        CertificateFactory factory = CertificateFactory.getInstance("X.509");
911        CertPathValidator validator =
912                CertPathValidator.getInstance(CertPathValidator.getDefaultType());
913        CertPath path = factory.generateCertPath(
914                Arrays.asList(caCert));
915        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
916        ks.load(null, null);
917        PKIXParameters params = new PKIXParameters(ks);
918        params.setRevocationEnabled(false);
919        validator.validate(path, params);
920    }
921
922    /**
923     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
924     * @param netId the integer that identifies the network configuration
925     * to the supplicant
926     * @return {@code true} if the operation succeeded
927     */
928    @Override
929    public boolean removeNetwork(int netId) {
930        enforceChangePermission();
931
932        if (mWifiStateMachineChannel != null) {
933            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
934        } else {
935            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
936            return false;
937        }
938    }
939
940    /**
941     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
942     * @param netId the integer that identifies the network configuration
943     * to the supplicant
944     * @param disableOthers if true, disable all other networks.
945     * @return {@code true} if the operation succeeded
946     */
947    @Override
948    public boolean enableNetwork(int netId, boolean disableOthers) {
949        enforceChangePermission();
950        if (mWifiStateMachineChannel != null) {
951            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
952                    disableOthers);
953        } else {
954            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
955            return false;
956        }
957    }
958
959    /**
960     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
961     * @param netId the integer that identifies the network configuration
962     * to the supplicant
963     * @return {@code true} if the operation succeeded
964     */
965    @Override
966    public boolean disableNetwork(int netId) {
967        enforceChangePermission();
968        if (mWifiStateMachineChannel != null) {
969            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
970        } else {
971            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
972            return false;
973        }
974    }
975
976    /**
977     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
978     * @return the Wi-Fi information, contained in {@link WifiInfo}.
979     */
980    @Override
981    public WifiInfo getConnectionInfo() {
982        enforceAccessPermission();
983        /*
984         * Make sure we have the latest information, by sending
985         * a status request to the supplicant.
986         */
987        return mWifiStateMachine.syncRequestConnectionInfo();
988    }
989
990    /**
991     * Return the results of the most recent access point scan, in the form of
992     * a list of {@link ScanResult} objects.
993     * @return the list of results
994     */
995    @Override
996    public List<ScanResult> getScanResults(String callingPackage) {
997        enforceAccessPermission();
998        int uid = Binder.getCallingUid();
999        long ident = Binder.clearCallingIdentity();
1000        try {
1001            if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
1002                      uid, Build.VERSION_CODES.M)) {
1003                return new ArrayList<ScanResult>();
1004            }
1005            if (mWifiScanner == null) {
1006                mWifiScanner = mWifiInjector.getWifiScanner();
1007            }
1008            return mWifiScanner.getSingleScanResults();
1009        } finally {
1010            Binder.restoreCallingIdentity(ident);
1011        }
1012    }
1013
1014    /**
1015     * Add a Hotspot 2.0 release 2 Management Object
1016     * @param mo The MO in XML form
1017     * @return -1 for failure
1018     */
1019    @Override
1020    public int addPasspointManagementObject(String mo) {
1021        return mWifiStateMachine.syncAddPasspointManagementObject(mWifiStateMachineChannel, mo);
1022    }
1023
1024    /**
1025     * Modify a Hotspot 2.0 release 2 Management Object
1026     * @param fqdn The FQDN of the service provider
1027     * @param mos A List of MO definitions to be updated
1028     * @return the number of nodes updated, or -1 for failure
1029     */
1030    @Override
1031    public int modifyPasspointManagementObject(String fqdn, List<PasspointManagementObjectDefinition> mos) {
1032        return mWifiStateMachine.syncModifyPasspointManagementObject(mWifiStateMachineChannel, fqdn, mos);
1033    }
1034
1035    /**
1036     * Query for a Hotspot 2.0 release 2 OSU icon
1037     * @param bssid The BSSID of the AP
1038     * @param fileName Icon file name
1039     */
1040    @Override
1041    public void queryPasspointIcon(long bssid, String fileName) {
1042        mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName);
1043    }
1044
1045    /**
1046     * Match the currently associated network against the SP matching the given FQDN
1047     * @param fqdn FQDN of the SP
1048     * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
1049     */
1050    @Override
1051    public int matchProviderWithCurrentNetwork(String fqdn) {
1052        return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
1053    }
1054
1055    /**
1056     * Deauthenticate and set the re-authentication hold off time for the current network
1057     * @param holdoff hold off time in milliseconds
1058     * @param ess set if the hold off pertains to an ESS rather than a BSS
1059     */
1060    @Override
1061    public void deauthenticateNetwork(long holdoff, boolean ess) {
1062        mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
1063    }
1064
1065    /**
1066     * Tell the supplicant to persist the current list of configured networks.
1067     * @return {@code true} if the operation succeeded
1068     *
1069     * TODO: deprecate this
1070     */
1071    @Override
1072    public boolean saveConfiguration() {
1073        enforceChangePermission();
1074        if (mWifiStateMachineChannel != null) {
1075            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1076        } else {
1077            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1078            return false;
1079        }
1080    }
1081
1082    /**
1083     * Set the country code
1084     * @param countryCode ISO 3166 country code.
1085     * @param persist {@code true} if the setting should be remembered.
1086     *
1087     * The persist behavior exists so that wifi can fall back to the last
1088     * persisted country code on a restart, when the locale information is
1089     * not available from telephony.
1090     */
1091    @Override
1092    public void setCountryCode(String countryCode, boolean persist) {
1093        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1094                " with persist set to " + persist);
1095        enforceConnectivityInternalPermission();
1096        final long token = Binder.clearCallingIdentity();
1097        try {
1098            if (mCountryCode.setCountryCode(countryCode, persist) && persist) {
1099                // Save this country code to persistent storage
1100                mFacade.setStringSetting(mContext,
1101                        Settings.Global.WIFI_COUNTRY_CODE,
1102                        countryCode);
1103            }
1104        } finally {
1105            Binder.restoreCallingIdentity(token);
1106        }
1107    }
1108
1109     /**
1110     * Get the country code
1111     * @return Get the best choice country code for wifi, regardless of if it was set or
1112     * not.
1113     * Returns null when there is no country code available.
1114     */
1115    @Override
1116    public String getCountryCode() {
1117        enforceConnectivityInternalPermission();
1118        String country = mCountryCode.getCountryCode();
1119        return country;
1120    }
1121
1122    @Override
1123    public boolean isDualBandSupported() {
1124        //TODO: Should move towards adding a driver API that checks at runtime
1125        return mContext.getResources().getBoolean(
1126                com.android.internal.R.bool.config_wifi_dual_band_support);
1127    }
1128
1129    /**
1130     * Return the DHCP-assigned addresses from the last successful DHCP request,
1131     * if any.
1132     * @return the DHCP information
1133     * @deprecated
1134     */
1135    @Override
1136    @Deprecated
1137    public DhcpInfo getDhcpInfo() {
1138        enforceAccessPermission();
1139        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1140
1141        DhcpInfo info = new DhcpInfo();
1142
1143        if (dhcpResults.ipAddress != null &&
1144                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1145            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1146        }
1147
1148        if (dhcpResults.gateway != null) {
1149            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1150        }
1151
1152        int dnsFound = 0;
1153        for (InetAddress dns : dhcpResults.dnsServers) {
1154            if (dns instanceof Inet4Address) {
1155                if (dnsFound == 0) {
1156                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1157                } else {
1158                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1159                }
1160                if (++dnsFound > 1) break;
1161            }
1162        }
1163        Inet4Address serverAddress = dhcpResults.serverAddress;
1164        if (serverAddress != null) {
1165            info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
1166        }
1167        info.leaseDuration = dhcpResults.leaseDuration;
1168
1169        return info;
1170    }
1171
1172    /**
1173     * enable TDLS for the local NIC to remote NIC
1174     * The APPs don't know the remote MAC address to identify NIC though,
1175     * so we need to do additional work to find it from remote IP address
1176     */
1177
1178    class TdlsTaskParams {
1179        public String remoteIpAddress;
1180        public boolean enable;
1181    }
1182
1183    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1184        @Override
1185        protected Integer doInBackground(TdlsTaskParams... params) {
1186
1187            // Retrieve parameters for the call
1188            TdlsTaskParams param = params[0];
1189            String remoteIpAddress = param.remoteIpAddress.trim();
1190            boolean enable = param.enable;
1191
1192            // Get MAC address of Remote IP
1193            String macAddress = null;
1194
1195            BufferedReader reader = null;
1196
1197            try {
1198                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1199
1200                // Skip over the line bearing colum titles
1201                String line = reader.readLine();
1202
1203                while ((line = reader.readLine()) != null) {
1204                    String[] tokens = line.split("[ ]+");
1205                    if (tokens.length < 6) {
1206                        continue;
1207                    }
1208
1209                    // ARP column format is
1210                    // Address HWType HWAddress Flags Mask IFace
1211                    String ip = tokens[0];
1212                    String mac = tokens[3];
1213
1214                    if (remoteIpAddress.equals(ip)) {
1215                        macAddress = mac;
1216                        break;
1217                    }
1218                }
1219
1220                if (macAddress == null) {
1221                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1222                            "/proc/net/arp");
1223                } else {
1224                    enableTdlsWithMacAddress(macAddress, enable);
1225                }
1226
1227            } catch (FileNotFoundException e) {
1228                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1229            } catch (IOException e) {
1230                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1231            } finally {
1232                try {
1233                    if (reader != null) {
1234                        reader.close();
1235                    }
1236                }
1237                catch (IOException e) {
1238                    // Do nothing
1239                }
1240            }
1241
1242            return 0;
1243        }
1244    }
1245
1246    @Override
1247    public void enableTdls(String remoteAddress, boolean enable) {
1248        if (remoteAddress == null) {
1249          throw new IllegalArgumentException("remoteAddress cannot be null");
1250        }
1251
1252        TdlsTaskParams params = new TdlsTaskParams();
1253        params.remoteIpAddress = remoteAddress;
1254        params.enable = enable;
1255        new TdlsTask().execute(params);
1256    }
1257
1258
1259    @Override
1260    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1261        if (remoteMacAddress == null) {
1262          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1263        }
1264
1265        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1266    }
1267
1268    /**
1269     * Get a reference to handler. This is used by a client to establish
1270     * an AsyncChannel communication with WifiService
1271     */
1272    @Override
1273    public Messenger getWifiServiceMessenger() {
1274        enforceAccessPermission();
1275        enforceChangePermission();
1276        return new Messenger(mClientHandler);
1277    }
1278
1279    /**
1280     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
1281     */
1282    @Override
1283    public void disableEphemeralNetwork(String SSID) {
1284        enforceAccessPermission();
1285        enforceChangePermission();
1286        mWifiStateMachine.disableEphemeralNetwork(SSID);
1287    }
1288
1289    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1290        @Override
1291        public void onReceive(Context context, Intent intent) {
1292            String action = intent.getAction();
1293            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1294                mWifiController.sendMessage(CMD_SCREEN_ON);
1295            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1296                mWifiController.sendMessage(CMD_USER_PRESENT);
1297            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1298                mWifiController.sendMessage(CMD_SCREEN_OFF);
1299            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1300                int pluggedType = intent.getIntExtra("plugged", 0);
1301                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1302            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1303                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1304                        BluetoothAdapter.STATE_DISCONNECTED);
1305                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1306            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1307                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1308                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1309            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
1310                boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
1311                mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
1312            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
1313                handleIdleModeChanged();
1314            }
1315        }
1316    };
1317
1318    /**
1319     * Observes settings changes to scan always mode.
1320     */
1321    private void registerForScanModeChange() {
1322        ContentObserver contentObserver = new ContentObserver(null) {
1323            @Override
1324            public void onChange(boolean selfChange) {
1325                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1326                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1327            }
1328        };
1329
1330        mContext.getContentResolver().registerContentObserver(
1331                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1332                false, contentObserver);
1333    }
1334
1335    private void registerForBroadcasts() {
1336        IntentFilter intentFilter = new IntentFilter();
1337        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1338        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1339        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1340        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1341        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1342        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1343        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1344        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1345
1346        boolean trackEmergencyCallState = mContext.getResources().getBoolean(
1347                com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
1348        if (trackEmergencyCallState) {
1349            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
1350        }
1351
1352        mContext.registerReceiver(mReceiver, intentFilter);
1353    }
1354
1355    private void registerForPackageOrUserRemoval() {
1356        IntentFilter intentFilter = new IntentFilter();
1357        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1358        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1359        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1360            @Override
1361            public void onReceive(Context context, Intent intent) {
1362                switch (intent.getAction()) {
1363                    case Intent.ACTION_PACKAGE_REMOVED: {
1364                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1365                            return;
1366                        }
1367                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1368                        Uri uri = intent.getData();
1369                        if (uid == -1 || uri == null) {
1370                            return;
1371                        }
1372                        String pkgName = uri.getSchemeSpecificPart();
1373                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
1374                        break;
1375                    }
1376                    case Intent.ACTION_USER_REMOVED: {
1377                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1378                        mWifiStateMachine.removeUserConfigs(userHandle);
1379                        break;
1380                    }
1381                }
1382            }
1383        }, UserHandle.ALL, intentFilter, null, null);
1384    }
1385
1386    @Override
1387    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1388        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1389                != PackageManager.PERMISSION_GRANTED) {
1390            pw.println("Permission Denial: can't dump WifiService from from pid="
1391                    + Binder.getCallingPid()
1392                    + ", uid=" + Binder.getCallingUid());
1393            return;
1394        }
1395        if (args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
1396            // WifiMetrics proto bytes were requested. Dump only these.
1397            mWifiStateMachine.updateWifiMetrics();
1398            mWifiMetrics.dump(fd, pw, args);
1399        } else if (args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
1400            // IpManager dump was requested. Pass it along and take no further action.
1401            String[] ipManagerArgs = new String[args.length - 1];
1402            System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
1403            mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
1404        } else if (args.length > 0 && DUMP_ARG_SET_IPREACH_DISCONNECT.equals(args[0])) {
1405            if (args.length > 1) {
1406                if (DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED.equals(args[1])) {
1407                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(true);
1408                } else if (DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED.equals(args[1])) {
1409                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(false);
1410                }
1411            }
1412            pw.println("IPREACH_DISCONNECT state is "
1413                    + mWifiStateMachine.getIpReachabilityDisconnectEnabled());
1414            return;
1415        } else {
1416            pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1417            pw.println("Stay-awake conditions: " +
1418                    Settings.Global.getInt(mContext.getContentResolver(),
1419                                           Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1420            pw.println("mInIdleMode " + mInIdleMode);
1421            pw.println("mScanPending " + mScanPending);
1422            mWifiController.dump(fd, pw, args);
1423            mSettingsStore.dump(fd, pw, args);
1424            mNotificationController.dump(fd, pw, args);
1425            mTrafficPoller.dump(fd, pw, args);
1426            pw.println();
1427            pw.println("Locks held:");
1428            mWifiLockManager.dump(pw);
1429            pw.println();
1430            mWifiMulticastLockManager.dump(pw);
1431            pw.println();
1432            mWifiStateMachine.dump(fd, pw, args);
1433            pw.println();
1434            mWifiBackupRestore.dump(fd, pw, args);
1435            pw.println();
1436        }
1437    }
1438
1439    @Override
1440    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1441        if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
1442            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1443            return true;
1444        }
1445        return false;
1446    }
1447
1448    @Override
1449    public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
1450        mWifiLockManager.updateWifiLockWorkSource(binder, ws);
1451    }
1452
1453    @Override
1454    public boolean releaseWifiLock(IBinder binder) {
1455        if (mWifiLockManager.releaseWifiLock(binder)) {
1456            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1457            return true;
1458        }
1459        return false;
1460    }
1461
1462    @Override
1463    public void initializeMulticastFiltering() {
1464        enforceMulticastChangePermission();
1465        mWifiMulticastLockManager.initializeFiltering();
1466    }
1467
1468    @Override
1469    public void acquireMulticastLock(IBinder binder, String tag) {
1470        enforceMulticastChangePermission();
1471        mWifiMulticastLockManager.acquireLock(binder, tag);
1472    }
1473
1474    @Override
1475    public void releaseMulticastLock() {
1476        enforceMulticastChangePermission();
1477        mWifiMulticastLockManager.releaseLock();
1478    }
1479
1480    @Override
1481    public boolean isMulticastEnabled() {
1482        enforceAccessPermission();
1483        return mWifiMulticastLockManager.isMulticastEnabled();
1484    }
1485
1486    @Override
1487    public void enableVerboseLogging(int verbose) {
1488        enforceAccessPermission();
1489        mFacade.setIntegerSetting(
1490                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
1491        enableVerboseLoggingInternal(verbose);
1492    }
1493
1494    private void enableVerboseLoggingInternal(int verbose) {
1495        mWifiStateMachine.enableVerboseLogging(verbose);
1496        mWifiLockManager.enableVerboseLogging(verbose);
1497        mWifiMulticastLockManager.enableVerboseLogging(verbose);
1498        mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
1499        mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
1500    }
1501
1502    @Override
1503    public int getVerboseLoggingLevel() {
1504        enforceAccessPermission();
1505        return mFacade.getIntegerSetting(
1506                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
1507    }
1508
1509    @Override
1510    public void enableAggressiveHandover(int enabled) {
1511        enforceAccessPermission();
1512        mWifiStateMachine.enableAggressiveHandover(enabled);
1513    }
1514
1515    @Override
1516    public int getAggressiveHandover() {
1517        enforceAccessPermission();
1518        return mWifiStateMachine.getAggressiveHandover();
1519    }
1520
1521    @Override
1522    public void setAllowScansWithTraffic(int enabled) {
1523        enforceAccessPermission();
1524        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1525    }
1526
1527    @Override
1528    public int getAllowScansWithTraffic() {
1529        enforceAccessPermission();
1530        return mWifiStateMachine.getAllowScansWithTraffic();
1531    }
1532
1533    @Override
1534    public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
1535        enforceChangePermission();
1536        return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
1537    }
1538
1539    @Override
1540    public boolean getEnableAutoJoinWhenAssociated() {
1541        enforceAccessPermission();
1542        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
1543    }
1544
1545    /* Return the Wifi Connection statistics object */
1546    @Override
1547    public WifiConnectionStatistics getConnectionStatistics() {
1548        enforceAccessPermission();
1549        enforceReadCredentialPermission();
1550        if (mWifiStateMachineChannel != null) {
1551            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1552        } else {
1553            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1554            return null;
1555        }
1556    }
1557
1558    @Override
1559    public void factoryReset() {
1560        enforceConnectivityInternalPermission();
1561
1562        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
1563            return;
1564        }
1565
1566        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1567            // Turn mobile hotspot off
1568            setWifiApEnabled(null, false);
1569        }
1570
1571        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
1572            // Enable wifi
1573            setWifiEnabled(true);
1574            // Delete all Wifi SSIDs
1575            List<WifiConfiguration> networks = getConfiguredNetworks();
1576            if (networks != null) {
1577                for (WifiConfiguration config : networks) {
1578                    removeNetwork(config.networkId);
1579                }
1580                saveConfiguration();
1581            }
1582        }
1583    }
1584
1585    /* private methods */
1586    static boolean logAndReturnFalse(String s) {
1587        Log.d(TAG, s);
1588        return false;
1589    }
1590
1591    public static boolean isValid(WifiConfiguration config) {
1592        String validity = checkValidity(config);
1593        return validity == null || logAndReturnFalse(validity);
1594    }
1595
1596    public static boolean isValidPasspoint(WifiConfiguration config) {
1597        String validity = checkPasspointValidity(config);
1598        return validity == null || logAndReturnFalse(validity);
1599    }
1600
1601    public static String checkValidity(WifiConfiguration config) {
1602        if (config.allowedKeyManagement == null)
1603            return "allowed kmgmt";
1604
1605        if (config.allowedKeyManagement.cardinality() > 1) {
1606            if (config.allowedKeyManagement.cardinality() != 2) {
1607                return "cardinality != 2";
1608            }
1609            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
1610                return "not WPA_EAP";
1611            }
1612            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
1613                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
1614                return "not PSK or 8021X";
1615            }
1616        }
1617        return null;
1618    }
1619
1620    public static String checkPasspointValidity(WifiConfiguration config) {
1621        if (!TextUtils.isEmpty(config.FQDN)) {
1622            /* this is passpoint configuration; it must not have an SSID */
1623            if (!TextUtils.isEmpty(config.SSID)) {
1624                return "SSID not expected for Passpoint: '" + config.SSID +
1625                        "' FQDN " + toHexString(config.FQDN);
1626            }
1627            /* this is passpoint configuration; it must have a providerFriendlyName */
1628            if (TextUtils.isEmpty(config.providerFriendlyName)) {
1629                return "no provider friendly name";
1630            }
1631            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
1632            /* this is passpoint configuration; it must have enterprise config */
1633            if (enterpriseConfig == null
1634                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
1635                return "no enterprise config";
1636            }
1637            if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
1638                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
1639                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
1640                    enterpriseConfig.getCaCertificate() == null) {
1641                return "no CA certificate";
1642            }
1643        }
1644        return null;
1645    }
1646
1647    @Override
1648    public Network getCurrentNetwork() {
1649        enforceAccessPermission();
1650        return mWifiStateMachine.getCurrentNetwork();
1651    }
1652
1653    public static String toHexString(String s) {
1654        if (s == null) {
1655            return "null";
1656        }
1657        StringBuilder sb = new StringBuilder();
1658        sb.append('\'').append(s).append('\'');
1659        for (int n = 0; n < s.length(); n++) {
1660            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
1661        }
1662        return sb.toString();
1663    }
1664
1665    public void hideCertFromUnaffiliatedUsers(String alias) {
1666        mCertManager.hideCertFromUnaffiliatedUsers(alias);
1667    }
1668
1669    public String[] listClientCertsForCurrentUser() {
1670        return mCertManager.listClientCertsForCurrentUser();
1671    }
1672
1673    /**
1674     * Enable/disable WifiConnectivityManager at runtime
1675     *
1676     * @param enabled true-enable; false-disable
1677     */
1678    @Override
1679    public void enableWifiConnectivityManager(boolean enabled) {
1680        enforceConnectivityInternalPermission();
1681        mWifiStateMachine.enableWifiConnectivityManager(enabled);
1682    }
1683
1684    /**
1685     * Retrieve the data to be backed to save the current state.
1686     *
1687     * @return  Raw byte stream of the data to be backed up.
1688     */
1689    @Override
1690    public byte[] retrieveBackupData() {
1691        enforceReadCredentialPermission();
1692        enforceAccessPermission();
1693        if (mWifiStateMachineChannel == null) {
1694            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1695            return null;
1696        }
1697
1698        Slog.d(TAG, "Retrieving backup data");
1699        List<WifiConfiguration> wifiConfigurations =
1700                mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
1701        byte[] backupData =
1702                mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
1703        Slog.d(TAG, "Retrieved backup data");
1704        return backupData;
1705    }
1706
1707    /**
1708     * Helper method to restore networks retrieved from backup data.
1709     *
1710     * @param configurations list of WifiConfiguration objects parsed from the backup data.
1711     */
1712    private void restoreNetworks(List<WifiConfiguration> configurations) {
1713        if (configurations == null) {
1714            Slog.e(TAG, "Backup data parse failed");
1715            return;
1716        }
1717        for (WifiConfiguration configuration : configurations) {
1718            int networkId = mWifiStateMachine.syncAddOrUpdateNetwork(
1719                    mWifiStateMachineChannel, configuration);
1720            if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1721                Slog.e(TAG, "Restore network failed: " + configuration.configKey());
1722                continue;
1723            }
1724            // Enable all networks restored.
1725            mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
1726        }
1727    }
1728
1729    /**
1730     * Restore state from the backed up data.
1731     *
1732     * @param data Raw byte stream of the backed up data.
1733     */
1734    @Override
1735    public void restoreBackupData(byte[] data) {
1736        enforceChangePermission();
1737        if (mWifiStateMachineChannel == null) {
1738            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1739            return;
1740        }
1741
1742        Slog.d(TAG, "Restoring backup data");
1743        List<WifiConfiguration> wifiConfigurations =
1744                mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
1745        restoreNetworks(wifiConfigurations);
1746        Slog.d(TAG, "Restored backup data");
1747    }
1748
1749    /**
1750     * Restore state from the older supplicant back up data.
1751     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
1752     *
1753     * @param supplicantData Raw byte stream of wpa_supplicant.conf
1754     * @param ipConfigData Raw byte stream of ipconfig.txt
1755     */
1756    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
1757        enforceChangePermission();
1758        if (mWifiStateMachineChannel == null) {
1759            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1760            return;
1761        }
1762
1763        Slog.d(TAG, "Restoring supplicant backup data");
1764        List<WifiConfiguration> wifiConfigurations =
1765                mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
1766                        supplicantData, ipConfigData);
1767        restoreNetworks(wifiConfigurations);
1768        Slog.d(TAG, "Restored supplicant backup data");
1769    }
1770}
1771