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