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