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