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