WifiServiceImpl.java revision e1d14389cd77b0757ba3533b122cf00ad65e2099
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     */
691    @Override
692    public WifiConfiguration getWifiApConfiguration() {
693        enforceAccessPermission();
694        mLog.trace("getWifiApConfiguration uid=%").c(Binder.getCallingUid()).flush();
695        return mWifiStateMachine.syncGetWifiApConfiguration();
696    }
697
698    /**
699     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
700     * @param wifiConfig WifiConfiguration details for soft access point
701     */
702    @Override
703    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
704        enforceChangePermission();
705        mLog.trace("setWifiApConfiguration uid=%").c(Binder.getCallingUid()).flush();
706        if (wifiConfig == null)
707            return;
708        if (isValid(wifiConfig)) {
709            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
710        } else {
711            Slog.e(TAG, "Invalid WifiConfiguration");
712        }
713    }
714
715    /**
716     * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
717     */
718    @Override
719    public boolean isScanAlwaysAvailable() {
720        enforceAccessPermission();
721        mLog.trace("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
722        return mSettingsStore.isScanAlwaysAvailable();
723    }
724
725    /**
726     * see {@link android.net.wifi.WifiManager#disconnect()}
727     */
728    @Override
729    public void disconnect() {
730        enforceChangePermission();
731        mLog.trace("disconnect uid=%").c(Binder.getCallingUid()).flush();
732        mWifiStateMachine.disconnectCommand();
733    }
734
735    /**
736     * see {@link android.net.wifi.WifiManager#reconnect()}
737     */
738    @Override
739    public void reconnect() {
740        enforceChangePermission();
741        mLog.trace("reconnect uid=%").c(Binder.getCallingUid()).flush();
742        mWifiStateMachine.reconnectCommand();
743    }
744
745    /**
746     * see {@link android.net.wifi.WifiManager#reassociate()}
747     */
748    @Override
749    public void reassociate() {
750        enforceChangePermission();
751        mLog.trace("reassociate uid=%").c(Binder.getCallingUid()).flush();
752        mWifiStateMachine.reassociateCommand();
753    }
754
755    /**
756     * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
757     */
758    @Override
759    public int getSupportedFeatures() {
760        enforceAccessPermission();
761        mLog.trace("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
762        if (mWifiStateMachineChannel != null) {
763            return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
764        } else {
765            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
766            return 0;
767        }
768    }
769
770    @Override
771    public void requestActivityInfo(ResultReceiver result) {
772        Bundle bundle = new Bundle();
773        mLog.trace("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
774        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
775        result.send(0, bundle);
776    }
777
778    /**
779     * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
780     */
781    @Override
782    public WifiActivityEnergyInfo reportActivityInfo() {
783        enforceAccessPermission();
784        mLog.trace("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
785        if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
786            return null;
787        }
788        WifiLinkLayerStats stats;
789        WifiActivityEnergyInfo energyInfo = null;
790        if (mWifiStateMachineChannel != null) {
791            stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
792            if (stats != null) {
793                final long rxIdleCurrent = mContext.getResources().getInteger(
794                        com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
795                final long rxCurrent = mContext.getResources().getInteger(
796                        com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
797                final long txCurrent = mContext.getResources().getInteger(
798                        com.android.internal.R.integer.config_wifi_tx_cur_ma);
799                final double voltage = mContext.getResources().getInteger(
800                        com.android.internal.R.integer.config_wifi_operating_voltage_mv)
801                        / 1000.0;
802
803                final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
804                final long[] txTimePerLevel;
805                if (stats.tx_time_per_level != null) {
806                    txTimePerLevel = new long[stats.tx_time_per_level.length];
807                    for (int i = 0; i < txTimePerLevel.length; i++) {
808                        txTimePerLevel[i] = stats.tx_time_per_level[i];
809                        // TODO(b/27227497): Need to read the power consumed per level from config
810                    }
811                } else {
812                    // This will happen if the HAL get link layer API returned null.
813                    txTimePerLevel = new long[0];
814                }
815                final long energyUsed = (long)((stats.tx_time * txCurrent +
816                        stats.rx_time * rxCurrent +
817                        rxIdleTime * rxIdleCurrent) * voltage);
818                if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
819                        stats.rx_time < 0 || energyUsed < 0) {
820                    StringBuilder sb = new StringBuilder();
821                    sb.append(" rxIdleCur=" + rxIdleCurrent);
822                    sb.append(" rxCur=" + rxCurrent);
823                    sb.append(" txCur=" + txCurrent);
824                    sb.append(" voltage=" + voltage);
825                    sb.append(" on_time=" + stats.on_time);
826                    sb.append(" tx_time=" + stats.tx_time);
827                    sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
828                    sb.append(" rx_time=" + stats.rx_time);
829                    sb.append(" rxIdleTime=" + rxIdleTime);
830                    sb.append(" energy=" + energyUsed);
831                    Log.d(TAG, " reportActivityInfo: " + sb.toString());
832                }
833
834                // Convert the LinkLayerStats into EnergyActivity
835                energyInfo = new WifiActivityEnergyInfo(SystemClock.elapsedRealtime(),
836                        WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
837                        txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed);
838            }
839            if (energyInfo != null && energyInfo.isValid()) {
840                return energyInfo;
841            } else {
842                return null;
843            }
844        } else {
845            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
846            return null;
847        }
848    }
849
850    /**
851     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
852     * @return the list of configured networks
853     */
854    @Override
855    public List<WifiConfiguration> getConfiguredNetworks() {
856        enforceAccessPermission();
857        mLog.trace("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
858        if (mWifiStateMachineChannel != null) {
859            return mWifiStateMachine.syncGetConfiguredNetworks(Binder.getCallingUid(),
860                    mWifiStateMachineChannel);
861        } else {
862            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
863            return null;
864        }
865    }
866
867    /**
868     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
869     * @return the list of configured networks with real preSharedKey
870     */
871    @Override
872    public List<WifiConfiguration> getPrivilegedConfiguredNetworks() {
873        enforceReadCredentialPermission();
874        enforceAccessPermission();
875        mLog.trace("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
876        if (mWifiStateMachineChannel != null) {
877            return mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
878        } else {
879            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
880            return null;
881        }
882    }
883
884    /**
885     * Returns a WifiConfiguration matching this ScanResult
886     * @param scanResult scanResult that represents the BSSID
887     * @return {@link WifiConfiguration} that matches this BSSID or null
888     */
889    @Override
890    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
891        enforceAccessPermission();
892        mLog.trace("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
893        return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
894    }
895
896    /**
897     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
898     * @return the supplicant-assigned identifier for the new or updated
899     * network if the operation succeeds, or {@code -1} if it fails
900     */
901    @Override
902    public int addOrUpdateNetwork(WifiConfiguration config) {
903        enforceChangePermission();
904        mLog.trace("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
905        if (isValid(config) && isValidPasspoint(config)) {
906
907            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
908
909            if (config.isPasspoint() &&
910                    (enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
911                            enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS)) {
912                if (config.updateIdentifier != null) {
913                    enforceAccessPermission();
914                }
915                else {
916                    try {
917                        verifyCert(enterpriseConfig.getCaCertificate());
918                    } catch (CertPathValidatorException cpve) {
919                        Slog.e(TAG, "CA Cert " +
920                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
921                                " untrusted: " + cpve.getMessage());
922                        return -1;
923                    } catch (GeneralSecurityException | IOException e) {
924                        Slog.e(TAG, "Failed to verify certificate" +
925                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
926                                ": " + e);
927                        return -1;
928                    }
929                }
930            }
931
932            //TODO: pass the Uid the WifiStateMachine as a message parameter
933            Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
934                    + " SSID " + config.SSID
935                    + " nid=" + Integer.toString(config.networkId));
936            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
937                config.creatorUid = Binder.getCallingUid();
938            } else {
939                config.lastUpdateUid = Binder.getCallingUid();
940            }
941            if (mWifiStateMachineChannel != null) {
942                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
943            } else {
944                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
945                return -1;
946            }
947        } else {
948            Slog.e(TAG, "bad network configuration");
949            return -1;
950        }
951    }
952
953    public static void verifyCert(X509Certificate caCert)
954            throws GeneralSecurityException, IOException {
955        CertificateFactory factory = CertificateFactory.getInstance("X.509");
956        CertPathValidator validator =
957                CertPathValidator.getInstance(CertPathValidator.getDefaultType());
958        CertPath path = factory.generateCertPath(
959                Arrays.asList(caCert));
960        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
961        ks.load(null, null);
962        PKIXParameters params = new PKIXParameters(ks);
963        params.setRevocationEnabled(false);
964        validator.validate(path, params);
965    }
966
967    /**
968     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
969     * @param netId the integer that identifies the network configuration
970     * to the supplicant
971     * @return {@code true} if the operation succeeded
972     */
973    @Override
974    public boolean removeNetwork(int netId) {
975        enforceChangePermission();
976        mLog.trace("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
977        // TODO Add private logging for netId b/33807876
978        if (mWifiStateMachineChannel != null) {
979            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
980        } else {
981            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
982            return false;
983        }
984    }
985
986    /**
987     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
988     * @param netId the integer that identifies the network configuration
989     * to the supplicant
990     * @param disableOthers if true, disable all other networks.
991     * @return {@code true} if the operation succeeded
992     */
993    @Override
994    public boolean enableNetwork(int netId, boolean disableOthers) {
995        enforceChangePermission();
996        // TODO b/33807876 Log netId
997        mLog.trace("enableNetwork uid=% disableOthers=%")
998                .c(Binder.getCallingUid())
999                .c(disableOthers).flush();
1000
1001        if (mWifiStateMachineChannel != null) {
1002            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
1003                    disableOthers);
1004        } else {
1005            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1006            return false;
1007        }
1008    }
1009
1010    /**
1011     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
1012     * @param netId the integer that identifies the network configuration
1013     * to the supplicant
1014     * @return {@code true} if the operation succeeded
1015     */
1016    @Override
1017    public boolean disableNetwork(int netId) {
1018        enforceChangePermission();
1019        // TODO b/33807876 Log netId
1020        mLog.trace("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
1021
1022        if (mWifiStateMachineChannel != null) {
1023            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
1024        } else {
1025            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1026            return false;
1027        }
1028    }
1029
1030    /**
1031     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
1032     * @return the Wi-Fi information, contained in {@link WifiInfo}.
1033     */
1034    @Override
1035    public WifiInfo getConnectionInfo() {
1036        enforceAccessPermission();
1037        mLog.trace("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
1038        /*
1039         * Make sure we have the latest information, by sending
1040         * a status request to the supplicant.
1041         */
1042        return mWifiStateMachine.syncRequestConnectionInfo();
1043    }
1044
1045    /**
1046     * Return the results of the most recent access point scan, in the form of
1047     * a list of {@link ScanResult} objects.
1048     * @return the list of results
1049     */
1050    @Override
1051    public List<ScanResult> getScanResults(String callingPackage) {
1052        enforceAccessPermission();
1053        int uid = Binder.getCallingUid();
1054        long ident = Binder.clearCallingIdentity();
1055        try {
1056            if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
1057                      uid, Build.VERSION_CODES.M)) {
1058                return new ArrayList<ScanResult>();
1059            }
1060            if (mWifiScanner == null) {
1061                mWifiScanner = mWifiInjector.getWifiScanner();
1062            }
1063            return mWifiScanner.getSingleScanResults();
1064        } finally {
1065            Binder.restoreCallingIdentity(ident);
1066        }
1067    }
1068
1069    /**
1070     * Add or update a Passpoint configuration.
1071     *
1072     * @param config The Passpoint configuration to be added
1073     * @return true on success or false on failure
1074     */
1075    @Override
1076    public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
1077        enforceChangePermission();
1078        mLog.trace("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1079        return mWifiStateMachine.syncAddOrUpdatePasspointConfig(mWifiStateMachineChannel, config);
1080    }
1081
1082    /**
1083     * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
1084     *
1085     * @param fqdn The FQDN of the Passpoint configuration to be removed
1086     * @return true on success or false on failure
1087     */
1088    @Override
1089    public boolean removePasspointConfiguration(String fqdn) {
1090        enforceChangePermission();
1091        mLog.trace("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1092        return mWifiStateMachine.syncRemovePasspointConfig(mWifiStateMachineChannel, fqdn);
1093    }
1094
1095    /**
1096     * Return the list of the installed Passpoint configurations.
1097     *
1098     * An empty list will be returned when no configuration is installed.
1099     *
1100     * @return A list of {@link PasspointConfiguration}
1101     */
1102    @Override
1103    public List<PasspointConfiguration> getPasspointConfigurations() {
1104        enforceAccessPermission();
1105        mLog.trace("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
1106        return mWifiStateMachine.syncGetPasspointConfigs(mWifiStateMachineChannel);
1107    }
1108
1109    /**
1110     * Query for a Hotspot 2.0 release 2 OSU icon
1111     * @param bssid The BSSID of the AP
1112     * @param fileName Icon file name
1113     */
1114    @Override
1115    public void queryPasspointIcon(long bssid, String fileName) {
1116        enforceAccessPermission();
1117        mLog.trace("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
1118        mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName);
1119    }
1120
1121    /**
1122     * Match the currently associated network against the SP matching the given FQDN
1123     * @param fqdn FQDN of the SP
1124     * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
1125     */
1126    @Override
1127    public int matchProviderWithCurrentNetwork(String fqdn) {
1128        mLog.trace("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
1129        return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
1130    }
1131
1132    /**
1133     * Deauthenticate and set the re-authentication hold off time for the current network
1134     * @param holdoff hold off time in milliseconds
1135     * @param ess set if the hold off pertains to an ESS rather than a BSS
1136     */
1137    @Override
1138    public void deauthenticateNetwork(long holdoff, boolean ess) {
1139        mLog.trace("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
1140        mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
1141    }
1142
1143    /**
1144     * Tell the supplicant to persist the current list of configured networks.
1145     * @return {@code true} if the operation succeeded
1146     *
1147     * TODO: deprecate this
1148     */
1149    @Override
1150    public boolean saveConfiguration() {
1151        enforceChangePermission();
1152        mLog.trace("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
1153        if (mWifiStateMachineChannel != null) {
1154            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1155        } else {
1156            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1157            return false;
1158        }
1159    }
1160
1161    /**
1162     * Set the country code
1163     * @param countryCode ISO 3166 country code.
1164     * @param persist {@code true} if the setting should be remembered.
1165     *
1166     * The persist behavior exists so that wifi can fall back to the last
1167     * persisted country code on a restart, when the locale information is
1168     * not available from telephony.
1169     */
1170    @Override
1171    public void setCountryCode(String countryCode, boolean persist) {
1172        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1173                " with persist set to " + persist);
1174        enforceConnectivityInternalPermission();
1175        mLog.trace("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
1176        // TODO b/35150708 Log list of channels when country code is updated
1177        final long token = Binder.clearCallingIdentity();
1178        try {
1179            if (mCountryCode.setCountryCode(countryCode, persist) && persist) {
1180                // Save this country code to persistent storage
1181                mFacade.setStringSetting(mContext,
1182                        Settings.Global.WIFI_COUNTRY_CODE,
1183                        countryCode);
1184            }
1185        } finally {
1186            Binder.restoreCallingIdentity(token);
1187        }
1188    }
1189
1190     /**
1191     * Get the country code
1192     * @return Get the best choice country code for wifi, regardless of if it was set or
1193     * not.
1194     * Returns null when there is no country code available.
1195     */
1196    @Override
1197    public String getCountryCode() {
1198        enforceConnectivityInternalPermission();
1199        mLog.trace("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
1200        String country = mCountryCode.getCountryCode();
1201        return country;
1202    }
1203
1204    @Override
1205    public boolean isDualBandSupported() {
1206        //TODO: Should move towards adding a driver API that checks at runtime
1207        mLog.trace("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
1208        return mContext.getResources().getBoolean(
1209                com.android.internal.R.bool.config_wifi_dual_band_support);
1210    }
1211
1212    /**
1213     * Return the DHCP-assigned addresses from the last successful DHCP request,
1214     * if any.
1215     * @return the DHCP information
1216     * @deprecated
1217     */
1218    @Override
1219    @Deprecated
1220    public DhcpInfo getDhcpInfo() {
1221        enforceAccessPermission();
1222        mLog.trace("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
1223        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1224
1225        DhcpInfo info = new DhcpInfo();
1226
1227        if (dhcpResults.ipAddress != null &&
1228                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1229            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1230        }
1231
1232        if (dhcpResults.gateway != null) {
1233            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1234        }
1235
1236        int dnsFound = 0;
1237        for (InetAddress dns : dhcpResults.dnsServers) {
1238            if (dns instanceof Inet4Address) {
1239                if (dnsFound == 0) {
1240                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1241                } else {
1242                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1243                }
1244                if (++dnsFound > 1) break;
1245            }
1246        }
1247        Inet4Address serverAddress = dhcpResults.serverAddress;
1248        if (serverAddress != null) {
1249            info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
1250        }
1251        info.leaseDuration = dhcpResults.leaseDuration;
1252
1253        return info;
1254    }
1255
1256    /**
1257     * enable TDLS for the local NIC to remote NIC
1258     * The APPs don't know the remote MAC address to identify NIC though,
1259     * so we need to do additional work to find it from remote IP address
1260     */
1261
1262    class TdlsTaskParams {
1263        public String remoteIpAddress;
1264        public boolean enable;
1265    }
1266
1267    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1268        @Override
1269        protected Integer doInBackground(TdlsTaskParams... params) {
1270
1271            // Retrieve parameters for the call
1272            TdlsTaskParams param = params[0];
1273            String remoteIpAddress = param.remoteIpAddress.trim();
1274            boolean enable = param.enable;
1275
1276            // Get MAC address of Remote IP
1277            String macAddress = null;
1278
1279            BufferedReader reader = null;
1280
1281            try {
1282                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1283
1284                // Skip over the line bearing colum titles
1285                String line = reader.readLine();
1286
1287                while ((line = reader.readLine()) != null) {
1288                    String[] tokens = line.split("[ ]+");
1289                    if (tokens.length < 6) {
1290                        continue;
1291                    }
1292
1293                    // ARP column format is
1294                    // Address HWType HWAddress Flags Mask IFace
1295                    String ip = tokens[0];
1296                    String mac = tokens[3];
1297
1298                    if (remoteIpAddress.equals(ip)) {
1299                        macAddress = mac;
1300                        break;
1301                    }
1302                }
1303
1304                if (macAddress == null) {
1305                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1306                            "/proc/net/arp");
1307                } else {
1308                    enableTdlsWithMacAddress(macAddress, enable);
1309                }
1310
1311            } catch (FileNotFoundException e) {
1312                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1313            } catch (IOException e) {
1314                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1315            } finally {
1316                try {
1317                    if (reader != null) {
1318                        reader.close();
1319                    }
1320                }
1321                catch (IOException e) {
1322                    // Do nothing
1323                }
1324            }
1325
1326            return 0;
1327        }
1328    }
1329
1330    @Override
1331    public void enableTdls(String remoteAddress, boolean enable) {
1332        if (remoteAddress == null) {
1333          throw new IllegalArgumentException("remoteAddress cannot be null");
1334        }
1335        mLog.trace("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
1336        TdlsTaskParams params = new TdlsTaskParams();
1337        params.remoteIpAddress = remoteAddress;
1338        params.enable = enable;
1339        new TdlsTask().execute(params);
1340    }
1341
1342
1343    @Override
1344    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1345        mLog.trace("enableTdlsWithMacAddress uid=% enable=%")
1346                .c(Binder.getCallingUid())
1347                .c(enable)
1348                .flush();
1349        if (remoteMacAddress == null) {
1350          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1351        }
1352
1353        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1354    }
1355
1356    /**
1357     * Get a reference to handler. This is used by a client to establish
1358     * an AsyncChannel communication with WifiService
1359     */
1360    @Override
1361    public Messenger getWifiServiceMessenger() {
1362        enforceAccessPermission();
1363        enforceChangePermission();
1364        mLog.trace("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
1365        return new Messenger(mClientHandler);
1366    }
1367
1368    /**
1369     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
1370     */
1371    @Override
1372    public void disableEphemeralNetwork(String SSID) {
1373        enforceAccessPermission();
1374        enforceChangePermission();
1375        mLog.trace("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
1376        mWifiStateMachine.disableEphemeralNetwork(SSID);
1377    }
1378
1379    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1380        @Override
1381        public void onReceive(Context context, Intent intent) {
1382            String action = intent.getAction();
1383            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1384                mWifiController.sendMessage(CMD_SCREEN_ON);
1385            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1386                mWifiController.sendMessage(CMD_USER_PRESENT);
1387            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1388                mWifiController.sendMessage(CMD_SCREEN_OFF);
1389            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1390                int pluggedType = intent.getIntExtra("plugged", 0);
1391                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1392            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1393                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1394                        BluetoothAdapter.STATE_DISCONNECTED);
1395                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1396            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1397                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1398                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1399            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
1400                boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
1401                mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
1402            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
1403                handleIdleModeChanged();
1404            }
1405        }
1406    };
1407
1408    private boolean startConsentUi(String packageName,
1409            int callingUid, String intentAction) throws RemoteException {
1410        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
1411            return false;
1412        }
1413        try {
1414            // Validate the package only if we are going to use it
1415            ApplicationInfo applicationInfo = mContext.getPackageManager()
1416                    .getApplicationInfoAsUser(packageName,
1417                            PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1418                            UserHandle.getUserId(callingUid));
1419            if (applicationInfo.uid != callingUid) {
1420                throw new SecurityException("Package " + callingUid
1421                        + " not in uid " + callingUid);
1422            }
1423
1424            // Permission review mode, trigger a user prompt
1425            Intent intent = new Intent(intentAction);
1426            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1427                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
1428            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
1429            mContext.startActivity(intent);
1430            return true;
1431        } catch (PackageManager.NameNotFoundException e) {
1432            throw new RemoteException(e.getMessage());
1433        }
1434    }
1435
1436    /**
1437     * Observes settings changes to scan always mode.
1438     */
1439    private void registerForScanModeChange() {
1440        ContentObserver contentObserver = new ContentObserver(null) {
1441            @Override
1442            public void onChange(boolean selfChange) {
1443                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1444                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1445            }
1446        };
1447
1448        mContext.getContentResolver().registerContentObserver(
1449                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1450                false, contentObserver);
1451    }
1452
1453    private void registerForBroadcasts() {
1454        IntentFilter intentFilter = new IntentFilter();
1455        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1456        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1457        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1458        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1459        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1460        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1461        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1462        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1463
1464        boolean trackEmergencyCallState = mContext.getResources().getBoolean(
1465                com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
1466        if (trackEmergencyCallState) {
1467            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
1468        }
1469
1470        mContext.registerReceiver(mReceiver, intentFilter);
1471    }
1472
1473    private void registerForPackageOrUserRemoval() {
1474        IntentFilter intentFilter = new IntentFilter();
1475        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1476        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1477        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1478            @Override
1479            public void onReceive(Context context, Intent intent) {
1480                switch (intent.getAction()) {
1481                    case Intent.ACTION_PACKAGE_REMOVED: {
1482                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1483                            return;
1484                        }
1485                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1486                        Uri uri = intent.getData();
1487                        if (uid == -1 || uri == null) {
1488                            return;
1489                        }
1490                        String pkgName = uri.getSchemeSpecificPart();
1491                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
1492                        break;
1493                    }
1494                    case Intent.ACTION_USER_REMOVED: {
1495                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1496                        mWifiStateMachine.removeUserConfigs(userHandle);
1497                        break;
1498                    }
1499                }
1500            }
1501        }, UserHandle.ALL, intentFilter, null, null);
1502    }
1503
1504    @Override
1505    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1506        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1507                != PackageManager.PERMISSION_GRANTED) {
1508            pw.println("Permission Denial: can't dump WifiService from from pid="
1509                    + Binder.getCallingPid()
1510                    + ", uid=" + Binder.getCallingUid());
1511            return;
1512        }
1513        if (args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
1514            // WifiMetrics proto bytes were requested. Dump only these.
1515            mWifiStateMachine.updateWifiMetrics();
1516            mWifiMetrics.dump(fd, pw, args);
1517        } else if (args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
1518            // IpManager dump was requested. Pass it along and take no further action.
1519            String[] ipManagerArgs = new String[args.length - 1];
1520            System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
1521            mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
1522        } else if (args.length > 0 && DUMP_ARG_SET_IPREACH_DISCONNECT.equals(args[0])) {
1523            if (args.length > 1) {
1524                if (DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED.equals(args[1])) {
1525                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(true);
1526                } else if (DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED.equals(args[1])) {
1527                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(false);
1528                }
1529            }
1530            pw.println("IPREACH_DISCONNECT state is "
1531                    + mWifiStateMachine.getIpReachabilityDisconnectEnabled());
1532            return;
1533        } else {
1534            pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1535            pw.println("Stay-awake conditions: " +
1536                    Settings.Global.getInt(mContext.getContentResolver(),
1537                                           Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1538            pw.println("mInIdleMode " + mInIdleMode);
1539            pw.println("mScanPending " + mScanPending);
1540            mWifiController.dump(fd, pw, args);
1541            mSettingsStore.dump(fd, pw, args);
1542            mTrafficPoller.dump(fd, pw, args);
1543            pw.println();
1544            pw.println("Locks held:");
1545            mWifiLockManager.dump(pw);
1546            pw.println();
1547            mWifiMulticastLockManager.dump(pw);
1548            pw.println();
1549            mWifiStateMachine.dump(fd, pw, args);
1550            pw.println();
1551            mWifiStateMachine.updateWifiMetrics();
1552            mWifiMetrics.dump(fd, pw, args);
1553            pw.println();
1554            mWifiBackupRestore.dump(fd, pw, args);
1555            pw.println();
1556        }
1557    }
1558
1559    @Override
1560    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1561        mLog.trace("acquireWifiLock uid=% lockMode=%")
1562                .c(Binder.getCallingUid())
1563                .c(lockMode).flush();
1564        if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
1565            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1566            return true;
1567        }
1568        return false;
1569    }
1570
1571    @Override
1572    public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
1573        mLog.trace("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
1574        mWifiLockManager.updateWifiLockWorkSource(binder, ws);
1575    }
1576
1577    @Override
1578    public boolean releaseWifiLock(IBinder binder) {
1579        mLog.trace("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
1580        if (mWifiLockManager.releaseWifiLock(binder)) {
1581            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1582            return true;
1583        }
1584        return false;
1585    }
1586
1587    @Override
1588    public void initializeMulticastFiltering() {
1589        enforceMulticastChangePermission();
1590        mLog.trace("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
1591        mWifiMulticastLockManager.initializeFiltering();
1592    }
1593
1594    @Override
1595    public void acquireMulticastLock(IBinder binder, String tag) {
1596        enforceMulticastChangePermission();
1597        mLog.trace("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
1598        mWifiMulticastLockManager.acquireLock(binder, tag);
1599    }
1600
1601    @Override
1602    public void releaseMulticastLock() {
1603        enforceMulticastChangePermission();
1604        mLog.trace("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
1605        mWifiMulticastLockManager.releaseLock();
1606    }
1607
1608    @Override
1609    public boolean isMulticastEnabled() {
1610        enforceAccessPermission();
1611        mLog.trace("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
1612        return mWifiMulticastLockManager.isMulticastEnabled();
1613    }
1614
1615    @Override
1616    public void enableVerboseLogging(int verbose) {
1617        enforceAccessPermission();
1618        mLog.trace("enableVerboseLogging uid=% verbose=%")
1619                .c(Binder.getCallingUid())
1620                .c(verbose).flush();
1621        mFacade.setIntegerSetting(
1622                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
1623        enableVerboseLoggingInternal(verbose);
1624    }
1625
1626    void enableVerboseLoggingInternal(int verbose) {
1627        mWifiStateMachine.enableVerboseLogging(verbose);
1628        mWifiLockManager.enableVerboseLogging(verbose);
1629        mWifiMulticastLockManager.enableVerboseLogging(verbose);
1630        mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
1631        mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
1632        LogcatLog.enableVerboseLogging(verbose);
1633    }
1634
1635    @Override
1636    public int getVerboseLoggingLevel() {
1637        enforceAccessPermission();
1638        mLog.trace("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
1639        return mFacade.getIntegerSetting(
1640                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
1641    }
1642
1643    @Override
1644    public void enableAggressiveHandover(int enabled) {
1645        enforceAccessPermission();
1646        mLog.trace("enableAggressiveHandover uid=% enabled=%")
1647            .c(Binder.getCallingUid())
1648            .c(enabled)
1649            .flush();
1650        mWifiStateMachine.enableAggressiveHandover(enabled);
1651    }
1652
1653    @Override
1654    public int getAggressiveHandover() {
1655        enforceAccessPermission();
1656        mLog.trace("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
1657        return mWifiStateMachine.getAggressiveHandover();
1658    }
1659
1660    @Override
1661    public void setAllowScansWithTraffic(int enabled) {
1662        enforceAccessPermission();
1663        mLog.trace("setAllowScansWithTraffic uid=% enabled=%")
1664                .c(Binder.getCallingUid())
1665                .c(enabled).flush();
1666        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1667    }
1668
1669    @Override
1670    public int getAllowScansWithTraffic() {
1671        enforceAccessPermission();
1672        mLog.trace("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
1673        return mWifiStateMachine.getAllowScansWithTraffic();
1674    }
1675
1676    @Override
1677    public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
1678        enforceChangePermission();
1679        mLog.trace("setEnableAutoJoinWhenAssociated uid=% enabled=%")
1680                .c(Binder.getCallingUid())
1681                .c(enabled).flush();
1682        return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
1683    }
1684
1685    @Override
1686    public boolean getEnableAutoJoinWhenAssociated() {
1687        enforceAccessPermission();
1688        mLog.trace("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
1689        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
1690    }
1691
1692    /* Return the Wifi Connection statistics object */
1693    @Override
1694    public WifiConnectionStatistics getConnectionStatistics() {
1695        enforceAccessPermission();
1696        enforceReadCredentialPermission();
1697        mLog.trace("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
1698        if (mWifiStateMachineChannel != null) {
1699            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1700        } else {
1701            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1702            return null;
1703        }
1704    }
1705
1706    @Override
1707    public void factoryReset() {
1708        enforceConnectivityInternalPermission();
1709        mLog.trace("factoryReset uid=%").c(Binder.getCallingUid()).flush();
1710        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
1711            return;
1712        }
1713
1714        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1715            // Turn mobile hotspot off
1716            setWifiApEnabled(null, false);
1717        }
1718
1719        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
1720            // Enable wifi
1721            try {
1722                setWifiEnabled(mContext.getOpPackageName(), true);
1723            } catch (RemoteException e) {
1724                /* ignore - local call */
1725            }
1726            // Delete all Wifi SSIDs
1727            List<WifiConfiguration> networks = getConfiguredNetworks();
1728            if (networks != null) {
1729                for (WifiConfiguration config : networks) {
1730                    removeNetwork(config.networkId);
1731                }
1732                saveConfiguration();
1733            }
1734        }
1735    }
1736
1737    /* private methods */
1738    static boolean logAndReturnFalse(String s) {
1739        Log.d(TAG, s);
1740        return false;
1741    }
1742
1743    public static boolean isValid(WifiConfiguration config) {
1744        String validity = checkValidity(config);
1745        return validity == null || logAndReturnFalse(validity);
1746    }
1747
1748    public static boolean isValidPasspoint(WifiConfiguration config) {
1749        String validity = checkPasspointValidity(config);
1750        return validity == null || logAndReturnFalse(validity);
1751    }
1752
1753    public static String checkValidity(WifiConfiguration config) {
1754        if (config.allowedKeyManagement == null)
1755            return "allowed kmgmt";
1756
1757        if (config.allowedKeyManagement.cardinality() > 1) {
1758            if (config.allowedKeyManagement.cardinality() != 2) {
1759                return "cardinality != 2";
1760            }
1761            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
1762                return "not WPA_EAP";
1763            }
1764            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
1765                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
1766                return "not PSK or 8021X";
1767            }
1768        }
1769        return null;
1770    }
1771
1772    public static String checkPasspointValidity(WifiConfiguration config) {
1773        if (!TextUtils.isEmpty(config.FQDN)) {
1774            /* this is passpoint configuration; it must not have an SSID */
1775            if (!TextUtils.isEmpty(config.SSID)) {
1776                return "SSID not expected for Passpoint: '" + config.SSID +
1777                        "' FQDN " + toHexString(config.FQDN);
1778            }
1779            /* this is passpoint configuration; it must have a providerFriendlyName */
1780            if (TextUtils.isEmpty(config.providerFriendlyName)) {
1781                return "no provider friendly name";
1782            }
1783            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
1784            /* this is passpoint configuration; it must have enterprise config */
1785            if (enterpriseConfig == null
1786                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
1787                return "no enterprise config";
1788            }
1789            if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
1790                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
1791                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
1792                    enterpriseConfig.getCaCertificate() == null) {
1793                return "no CA certificate";
1794            }
1795        }
1796        return null;
1797    }
1798
1799    @Override
1800    public Network getCurrentNetwork() {
1801        enforceAccessPermission();
1802        mLog.trace("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
1803        return mWifiStateMachine.getCurrentNetwork();
1804    }
1805
1806    public static String toHexString(String s) {
1807        if (s == null) {
1808            return "null";
1809        }
1810        StringBuilder sb = new StringBuilder();
1811        sb.append('\'').append(s).append('\'');
1812        for (int n = 0; n < s.length(); n++) {
1813            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
1814        }
1815        return sb.toString();
1816    }
1817
1818    public void hideCertFromUnaffiliatedUsers(String alias) {
1819        mCertManager.hideCertFromUnaffiliatedUsers(alias);
1820    }
1821
1822    public String[] listClientCertsForCurrentUser() {
1823        return mCertManager.listClientCertsForCurrentUser();
1824    }
1825
1826    /**
1827     * Enable/disable WifiConnectivityManager at runtime
1828     *
1829     * @param enabled true-enable; false-disable
1830     */
1831    @Override
1832    public void enableWifiConnectivityManager(boolean enabled) {
1833        enforceConnectivityInternalPermission();
1834        mLog.trace("enableWifiConnectivityManager uid=% enabled=%")
1835            .c(Binder.getCallingUid())
1836            .c(enabled).flush();
1837        mWifiStateMachine.enableWifiConnectivityManager(enabled);
1838    }
1839
1840    /**
1841     * Retrieve the data to be backed to save the current state.
1842     *
1843     * @return  Raw byte stream of the data to be backed up.
1844     */
1845    @Override
1846    public byte[] retrieveBackupData() {
1847        enforceReadCredentialPermission();
1848        enforceAccessPermission();
1849        mLog.trace("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
1850        if (mWifiStateMachineChannel == null) {
1851            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1852            return null;
1853        }
1854
1855        Slog.d(TAG, "Retrieving backup data");
1856        List<WifiConfiguration> wifiConfigurations =
1857                mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
1858        byte[] backupData =
1859                mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
1860        Slog.d(TAG, "Retrieved backup data");
1861        return backupData;
1862    }
1863
1864    /**
1865     * Helper method to restore networks retrieved from backup data.
1866     *
1867     * @param configurations list of WifiConfiguration objects parsed from the backup data.
1868     */
1869    private void restoreNetworks(List<WifiConfiguration> configurations) {
1870        if (configurations == null) {
1871            Slog.e(TAG, "Backup data parse failed");
1872            return;
1873        }
1874        for (WifiConfiguration configuration : configurations) {
1875            int networkId = mWifiStateMachine.syncAddOrUpdateNetwork(
1876                    mWifiStateMachineChannel, configuration);
1877            if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1878                Slog.e(TAG, "Restore network failed: " + configuration.configKey());
1879                continue;
1880            }
1881            // Enable all networks restored.
1882            mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
1883        }
1884    }
1885
1886    /**
1887     * Restore state from the backed up data.
1888     *
1889     * @param data Raw byte stream of the backed up data.
1890     */
1891    @Override
1892    public void restoreBackupData(byte[] data) {
1893        enforceChangePermission();
1894        mLog.trace("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
1895        if (mWifiStateMachineChannel == null) {
1896            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1897            return;
1898        }
1899
1900        Slog.d(TAG, "Restoring backup data");
1901        List<WifiConfiguration> wifiConfigurations =
1902                mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
1903        restoreNetworks(wifiConfigurations);
1904        Slog.d(TAG, "Restored backup data");
1905    }
1906
1907    /**
1908     * Restore state from the older supplicant back up data.
1909     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
1910     *
1911     * @param supplicantData Raw byte stream of wpa_supplicant.conf
1912     * @param ipConfigData Raw byte stream of ipconfig.txt
1913     */
1914    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
1915        enforceChangePermission();
1916        mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
1917        if (mWifiStateMachineChannel == null) {
1918            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1919            return;
1920        }
1921
1922        Slog.d(TAG, "Restoring supplicant backup data");
1923        List<WifiConfiguration> wifiConfigurations =
1924                mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
1925                        supplicantData, ipConfigData);
1926        restoreNetworks(wifiConfigurations);
1927        Slog.d(TAG, "Restored supplicant backup data");
1928    }
1929}
1930