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