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