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