WifiServiceImpl.java revision c9aab08c8e0eb78f8da4e1ffe962b09a9cf0a8a1
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.connectivity.tethering.IControlsTethering.STATE_TETHERED;
20import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
21import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
22import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
23import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
24import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
25import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
26import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
27import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
28import static com.android.server.wifi.WifiController.CMD_SET_AP;
29import static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
30import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
31
32import android.Manifest;
33import android.app.AppOpsManager;
34import android.bluetooth.BluetoothAdapter;
35import android.content.BroadcastReceiver;
36import android.content.Context;
37import android.content.Intent;
38import android.content.IntentFilter;
39import android.content.pm.ApplicationInfo;
40import android.content.pm.PackageManager;
41import android.content.pm.ParceledListSlice;
42import android.database.ContentObserver;
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 = mWifiInjector.getUserManager();
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 enforceNetworkStackPermission() {
549        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
550                "WifiService");
551    }
552
553    private void enforceAccessPermission() {
554        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
555                "WifiService");
556    }
557
558    private void enforceChangePermission() {
559        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
560                "WifiService");
561    }
562
563    private void enforceLocationHardwarePermission() {
564        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE,
565                "LocationHardware");
566    }
567
568    private void enforceReadCredentialPermission() {
569        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
570                                                "WifiService");
571    }
572
573    private void enforceWorkSourcePermission() {
574        mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
575                "WifiService");
576
577    }
578
579    private void enforceMulticastChangePermission() {
580        mContext.enforceCallingOrSelfPermission(
581                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
582                "WifiService");
583    }
584
585    private void enforceConnectivityInternalPermission() {
586        mContext.enforceCallingOrSelfPermission(
587                android.Manifest.permission.CONNECTIVITY_INTERNAL,
588                "ConnectivityService");
589    }
590
591    /**
592     * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
593     * @param enable {@code true} to enable, {@code false} to disable.
594     * @return {@code true} if the enable/disable operation was
595     *         started or is already in the queue.
596     */
597    @Override
598    public synchronized boolean setWifiEnabled(String packageName, boolean enable)
599            throws RemoteException {
600        enforceChangePermission();
601        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
602                    + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
603        mLog.trace("setWifiEnabled package=% uid=% enable=%").c(packageName)
604                .c(Binder.getCallingUid()).c(enable).flush();
605
606        // If SoftAp is enabled, only Settings is allowed to toggle wifi
607        boolean apEnabled =
608                mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
609        boolean isFromSettings =
610                packageName.equals(SYSUI_PACKAGE_NAME) || packageName.equals(SETTINGS_PACKAGE_NAME);
611        if (apEnabled && !isFromSettings) {
612            mLog.trace("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
613            return false;
614        }
615
616        /*
617        * Caller might not have WRITE_SECURE_SETTINGS,
618        * only CHANGE_WIFI_STATE is enforced
619        */
620        long ident = Binder.clearCallingIdentity();
621        try {
622            if (! mSettingsStore.handleWifiToggled(enable)) {
623                // Nothing to do if wifi cannot be toggled
624                return true;
625            }
626        } finally {
627            Binder.restoreCallingIdentity(ident);
628        }
629
630
631        if (mPermissionReviewRequired) {
632            final int wiFiEnabledState = getWifiEnabledState();
633            if (enable) {
634                if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
635                        || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
636                    if (startConsentUi(packageName, Binder.getCallingUid(),
637                            WifiManager.ACTION_REQUEST_ENABLE)) {
638                        return true;
639                    }
640                }
641            } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
642                    || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
643                if (startConsentUi(packageName, Binder.getCallingUid(),
644                        WifiManager.ACTION_REQUEST_DISABLE)) {
645                    return true;
646                }
647            }
648        }
649
650        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
651        return true;
652    }
653
654    /**
655     * see {@link WifiManager#getWifiState()}
656     * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
657     *         {@link WifiManager#WIFI_STATE_DISABLING},
658     *         {@link WifiManager#WIFI_STATE_ENABLED},
659     *         {@link WifiManager#WIFI_STATE_ENABLING},
660     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
661     */
662    @Override
663    public int getWifiEnabledState() {
664        enforceAccessPermission();
665        mLog.trace("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
666        return mWifiStateMachine.syncGetWifiState();
667    }
668
669    /**
670     * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
671     * @param wifiConfig SSID, security and channel details as
672     *        part of WifiConfiguration
673     * @param enabled true to enable and false to disable
674     */
675    @Override
676    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
677        enforceChangePermission();
678        mWifiPermissionsUtil.enforceTetherChangePermission(mContext);
679
680        mLog.trace("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
681
682        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
683            throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
684        }
685        // null wifiConfig is a meaningful input for CMD_SET_AP
686        if (wifiConfig == null || isValid(wifiConfig)) {
687            mWifiController.sendMessage(CMD_SET_AP, enabled ? 1 : 0, 0, wifiConfig);
688        } else {
689            Slog.e(TAG, "Invalid WifiConfiguration");
690        }
691    }
692
693    /**
694     * see {@link WifiManager#getWifiApState()}
695     * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
696     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
697     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
698     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
699     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
700     */
701    @Override
702    public int getWifiApEnabledState() {
703        enforceAccessPermission();
704        mLog.trace("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
705        return mWifiStateMachine.syncGetWifiApState();
706    }
707
708    /**
709     * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
710     *
711     * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
712     *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
713     *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
714     *
715     * @param ifaceName String name of the updated interface
716     * @param mode new operating mode of the interface
717     *
718     * @throws SecurityException if the caller does not have permission to call update
719     */
720    @Override
721    public void updateInterfaceIpState(String ifaceName, int mode) {
722        // NETWORK_STACK is a signature only permission.
723        enforceNetworkStackPermission();
724
725        Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode);
726        // TODO: keep track of modes in a datastructure - protect it with a lock of some sort.
727        // TODO: check the mode when startLOHS comes in in case it is already active
728        // TODO: if mode == LOCAL_ONLY, trigger onStarted callbacks
729    }
730
731    /**
732     * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
733     * @param wifiConfig SSID, security and channel details as
734     *        part of WifiConfiguration
735     * @return {@code true} if softap start was triggered
736     * @throws SecurityException if the caller does not have permission to start softap
737     */
738    @Override
739    public boolean startSoftAp(WifiConfiguration wifiConfig) {
740        // NETWORK_STACK is a signature only permission.
741        enforceNetworkStackPermission();
742
743        mLog.trace("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
744
745        return startSoftApInternal(wifiConfig, STATE_TETHERED);
746    }
747
748    private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
749        mLog.trace("startSoftApInternal uid=% mode=%")
750                .c(Binder.getCallingUid()).c(mode).flush();
751
752        // null wifiConfig is a meaningful input for CMD_SET_AP
753        if (wifiConfig == null || isValid(wifiConfig)) {
754            // TODO: need a way to set the mode
755            mWifiController.sendMessage(CMD_SET_AP, 1, 0, wifiConfig);
756            return true;
757        }
758        Slog.e(TAG, "Invalid WifiConfiguration");
759        return false;
760    }
761
762    /**
763     * see {@link android.net.wifi.WifiManager#stopSoftAp()}
764     * @return {@code true} if softap stop was triggered
765     * @throws SecurityException if the caller does not have permission to stop softap
766     */
767    @Override
768    public boolean stopSoftAp() {
769        // NETWORK_STACK is a signature only permission.
770        enforceNetworkStackPermission();
771
772        mLog.trace("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
773
774        // add checks here to make sure this is the proper caller - apps can't disable tethering or
775        // instances of local only hotspot that they didn't start.  return false for those cases
776
777        return stopSoftApInternal();
778    }
779
780    /**
781     * Internal method to stop softap mode.  Callers of this method should have already checked
782     * proper permissions beyond the NetworkStack permission.
783     */
784    private boolean stopSoftApInternal() {
785        mLog.trace("stopSoftApInternal uid=%").c(Binder.getCallingUid()).flush();
786
787        mWifiController.sendMessage(CMD_SET_AP, 0, 0);
788        return true;
789    }
790
791    /**
792     * see {@link WifiManager#getWifiApConfiguration()}
793     * @return soft access point configuration
794     * @throws SecurityException if the caller does not have permission to retrieve the softap
795     * config
796     */
797    @Override
798    public WifiConfiguration getWifiApConfiguration() {
799        enforceAccessPermission();
800        int uid = Binder.getCallingUid();
801        // only allow Settings UI to get the saved SoftApConfig
802        if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
803            // random apps should not be allowed to read the user specified config
804            throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
805                    + "(uid = " + uid + ")");
806        }
807        mLog.trace("getWifiApConfiguration uid=%").c(uid).flush();
808        return mWifiStateMachine.syncGetWifiApConfiguration();
809    }
810
811    /**
812     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
813     * @param wifiConfig WifiConfiguration details for soft access point
814     * @throws SecurityException if the caller does not have permission to write the sotap config
815     */
816    @Override
817    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
818        enforceChangePermission();
819        int uid = Binder.getCallingUid();
820        // only allow Settings UI to write the stored SoftApConfig
821        if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
822            // random apps should not be allowed to read the user specified config
823            throw new SecurityException("App not allowed to read or update stored WiFi AP config "
824                    + "(uid = " + uid + ")");
825        }
826        mLog.trace("setWifiApConfiguration uid=%").c(uid).flush();
827        if (wifiConfig == null)
828            return;
829        if (isValid(wifiConfig)) {
830            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
831        } else {
832            Slog.e(TAG, "Invalid WifiConfiguration");
833        }
834    }
835
836    /**
837     * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
838     */
839    @Override
840    public boolean isScanAlwaysAvailable() {
841        enforceAccessPermission();
842        mLog.trace("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
843        return mSettingsStore.isScanAlwaysAvailable();
844    }
845
846    /**
847     * see {@link android.net.wifi.WifiManager#disconnect()}
848     */
849    @Override
850    public void disconnect() {
851        enforceChangePermission();
852        mLog.trace("disconnect uid=%").c(Binder.getCallingUid()).flush();
853        mWifiStateMachine.disconnectCommand();
854    }
855
856    /**
857     * see {@link android.net.wifi.WifiManager#reconnect()}
858     */
859    @Override
860    public void reconnect() {
861        enforceChangePermission();
862        mLog.trace("reconnect uid=%").c(Binder.getCallingUid()).flush();
863        mWifiStateMachine.reconnectCommand();
864    }
865
866    /**
867     * see {@link android.net.wifi.WifiManager#reassociate()}
868     */
869    @Override
870    public void reassociate() {
871        enforceChangePermission();
872        mLog.trace("reassociate uid=%").c(Binder.getCallingUid()).flush();
873        mWifiStateMachine.reassociateCommand();
874    }
875
876    /**
877     * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
878     */
879    @Override
880    public int getSupportedFeatures() {
881        enforceAccessPermission();
882        mLog.trace("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
883        if (mWifiStateMachineChannel != null) {
884            return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
885        } else {
886            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
887            return 0;
888        }
889    }
890
891    @Override
892    public void requestActivityInfo(ResultReceiver result) {
893        Bundle bundle = new Bundle();
894        mLog.trace("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
895        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
896        result.send(0, bundle);
897    }
898
899    /**
900     * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
901     */
902    @Override
903    public WifiActivityEnergyInfo reportActivityInfo() {
904        enforceAccessPermission();
905        mLog.trace("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
906        if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
907            return null;
908        }
909        WifiLinkLayerStats stats;
910        WifiActivityEnergyInfo energyInfo = null;
911        if (mWifiStateMachineChannel != null) {
912            stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
913            if (stats != null) {
914                final long rxIdleCurrent = mContext.getResources().getInteger(
915                        com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
916                final long rxCurrent = mContext.getResources().getInteger(
917                        com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
918                final long txCurrent = mContext.getResources().getInteger(
919                        com.android.internal.R.integer.config_wifi_tx_cur_ma);
920                final double voltage = mContext.getResources().getInteger(
921                        com.android.internal.R.integer.config_wifi_operating_voltage_mv)
922                        / 1000.0;
923
924                final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
925                final long[] txTimePerLevel;
926                if (stats.tx_time_per_level != null) {
927                    txTimePerLevel = new long[stats.tx_time_per_level.length];
928                    for (int i = 0; i < txTimePerLevel.length; i++) {
929                        txTimePerLevel[i] = stats.tx_time_per_level[i];
930                        // TODO(b/27227497): Need to read the power consumed per level from config
931                    }
932                } else {
933                    // This will happen if the HAL get link layer API returned null.
934                    txTimePerLevel = new long[0];
935                }
936                final long energyUsed = (long)((stats.tx_time * txCurrent +
937                        stats.rx_time * rxCurrent +
938                        rxIdleTime * rxIdleCurrent) * voltage);
939                if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
940                        stats.rx_time < 0 || energyUsed < 0) {
941                    StringBuilder sb = new StringBuilder();
942                    sb.append(" rxIdleCur=" + rxIdleCurrent);
943                    sb.append(" rxCur=" + rxCurrent);
944                    sb.append(" txCur=" + txCurrent);
945                    sb.append(" voltage=" + voltage);
946                    sb.append(" on_time=" + stats.on_time);
947                    sb.append(" tx_time=" + stats.tx_time);
948                    sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
949                    sb.append(" rx_time=" + stats.rx_time);
950                    sb.append(" rxIdleTime=" + rxIdleTime);
951                    sb.append(" energy=" + energyUsed);
952                    Log.d(TAG, " reportActivityInfo: " + sb.toString());
953                }
954
955                // Convert the LinkLayerStats into EnergyActivity
956                energyInfo = new WifiActivityEnergyInfo(SystemClock.elapsedRealtime(),
957                        WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
958                        txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed);
959            }
960            if (energyInfo != null && energyInfo.isValid()) {
961                return energyInfo;
962            } else {
963                return null;
964            }
965        } else {
966            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
967            return null;
968        }
969    }
970
971    /**
972     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
973     * @return the list of configured networks
974     */
975    @Override
976    public ParceledListSlice<WifiConfiguration> getConfiguredNetworks() {
977        enforceAccessPermission();
978        mLog.trace("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
979        if (mWifiStateMachineChannel != null) {
980            List<WifiConfiguration> configs = mWifiStateMachine.syncGetConfiguredNetworks(
981                    Binder.getCallingUid(), mWifiStateMachineChannel);
982            if (configs != null) {
983                return new ParceledListSlice<WifiConfiguration>(configs);
984            }
985        } else {
986            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
987        }
988        return null;
989    }
990
991    /**
992     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
993     * @return the list of configured networks with real preSharedKey
994     */
995    @Override
996    public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks() {
997        enforceReadCredentialPermission();
998        enforceAccessPermission();
999        mLog.trace("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
1000        if (mWifiStateMachineChannel != null) {
1001            List<WifiConfiguration> configs =
1002                    mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
1003            if (configs != null) {
1004                return new ParceledListSlice<WifiConfiguration>(configs);
1005            }
1006        } else {
1007            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1008        }
1009        return null;
1010    }
1011
1012    /**
1013     * Returns a WifiConfiguration for a Passpoint network matching this ScanResult.
1014     *
1015     * @param scanResult scanResult that represents the BSSID
1016     * @return {@link WifiConfiguration} that matches this BSSID or null
1017     */
1018    @Override
1019    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
1020        enforceAccessPermission();
1021        mLog.trace("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
1022        if (!mContext.getResources().getBoolean(
1023                com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
1024            throw new UnsupportedOperationException("Passpoint not enabled");
1025        }
1026        return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
1027    }
1028
1029    /**
1030     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
1031     * @return the supplicant-assigned identifier for the new or updated
1032     * network if the operation succeeds, or {@code -1} if it fails
1033     */
1034    @Override
1035    public int addOrUpdateNetwork(WifiConfiguration config) {
1036        enforceChangePermission();
1037        mLog.trace("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
1038        if (isValid(config) && isValidPasspoint(config)) {
1039
1040            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
1041
1042            if (config.isPasspoint() &&
1043                    (enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
1044                            enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS)) {
1045                if (config.updateIdentifier != null) {
1046                    enforceAccessPermission();
1047                }
1048                else {
1049                    try {
1050                        verifyCert(enterpriseConfig.getCaCertificate());
1051                    } catch (CertPathValidatorException cpve) {
1052                        Slog.e(TAG, "CA Cert " +
1053                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
1054                                " untrusted: " + cpve.getMessage());
1055                        return -1;
1056                    } catch (GeneralSecurityException | IOException e) {
1057                        Slog.e(TAG, "Failed to verify certificate" +
1058                                enterpriseConfig.getCaCertificate().getSubjectX500Principal() +
1059                                ": " + e);
1060                        return -1;
1061                    }
1062                }
1063            }
1064
1065            //TODO: pass the Uid the WifiStateMachine as a message parameter
1066            Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
1067                    + " SSID " + config.SSID
1068                    + " nid=" + Integer.toString(config.networkId));
1069            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1070                config.creatorUid = Binder.getCallingUid();
1071            } else {
1072                config.lastUpdateUid = Binder.getCallingUid();
1073            }
1074            if (mWifiStateMachineChannel != null) {
1075                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
1076            } else {
1077                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1078                return -1;
1079            }
1080        } else {
1081            Slog.e(TAG, "bad network configuration");
1082            return -1;
1083        }
1084    }
1085
1086    public static void verifyCert(X509Certificate caCert)
1087            throws GeneralSecurityException, IOException {
1088        CertificateFactory factory = CertificateFactory.getInstance("X.509");
1089        CertPathValidator validator =
1090                CertPathValidator.getInstance(CertPathValidator.getDefaultType());
1091        CertPath path = factory.generateCertPath(
1092                Arrays.asList(caCert));
1093        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
1094        ks.load(null, null);
1095        PKIXParameters params = new PKIXParameters(ks);
1096        params.setRevocationEnabled(false);
1097        validator.validate(path, params);
1098    }
1099
1100    /**
1101     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
1102     * @param netId the integer that identifies the network configuration
1103     * to the supplicant
1104     * @return {@code true} if the operation succeeded
1105     */
1106    @Override
1107    public boolean removeNetwork(int netId) {
1108        enforceChangePermission();
1109        mLog.trace("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
1110        // TODO Add private logging for netId b/33807876
1111        if (mWifiStateMachineChannel != null) {
1112            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
1113        } else {
1114            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1115            return false;
1116        }
1117    }
1118
1119    /**
1120     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
1121     * @param netId the integer that identifies the network configuration
1122     * to the supplicant
1123     * @param disableOthers if true, disable all other networks.
1124     * @return {@code true} if the operation succeeded
1125     */
1126    @Override
1127    public boolean enableNetwork(int netId, boolean disableOthers) {
1128        enforceChangePermission();
1129        // TODO b/33807876 Log netId
1130        mLog.trace("enableNetwork uid=% disableOthers=%")
1131                .c(Binder.getCallingUid())
1132                .c(disableOthers).flush();
1133
1134        if (mWifiStateMachineChannel != null) {
1135            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
1136                    disableOthers);
1137        } else {
1138            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1139            return false;
1140        }
1141    }
1142
1143    /**
1144     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
1145     * @param netId the integer that identifies the network configuration
1146     * to the supplicant
1147     * @return {@code true} if the operation succeeded
1148     */
1149    @Override
1150    public boolean disableNetwork(int netId) {
1151        enforceChangePermission();
1152        // TODO b/33807876 Log netId
1153        mLog.trace("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
1154
1155        if (mWifiStateMachineChannel != null) {
1156            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
1157        } else {
1158            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1159            return false;
1160        }
1161    }
1162
1163    /**
1164     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
1165     * @return the Wi-Fi information, contained in {@link WifiInfo}.
1166     */
1167    @Override
1168    public WifiInfo getConnectionInfo() {
1169        enforceAccessPermission();
1170        mLog.trace("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
1171        /*
1172         * Make sure we have the latest information, by sending
1173         * a status request to the supplicant.
1174         */
1175        return mWifiStateMachine.syncRequestConnectionInfo();
1176    }
1177
1178    /**
1179     * Return the results of the most recent access point scan, in the form of
1180     * a list of {@link ScanResult} objects.
1181     * @return the list of results
1182     */
1183    @Override
1184    public List<ScanResult> getScanResults(String callingPackage) {
1185        enforceAccessPermission();
1186        int uid = Binder.getCallingUid();
1187        long ident = Binder.clearCallingIdentity();
1188        try {
1189            if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
1190                      uid, Build.VERSION_CODES.M)) {
1191                return new ArrayList<ScanResult>();
1192            }
1193            if (mWifiScanner == null) {
1194                mWifiScanner = mWifiInjector.getWifiScanner();
1195            }
1196            return mWifiScanner.getSingleScanResults();
1197        } finally {
1198            Binder.restoreCallingIdentity(ident);
1199        }
1200    }
1201
1202    /**
1203     * Add or update a Passpoint configuration.
1204     *
1205     * @param config The Passpoint configuration to be added
1206     * @return true on success or false on failure
1207     */
1208    @Override
1209    public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
1210        enforceChangePermission();
1211        mLog.trace("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1212        if (!mContext.getResources().getBoolean(
1213                com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
1214            throw new UnsupportedOperationException("Passpoint not enabled");
1215        }
1216        return mWifiStateMachine.syncAddOrUpdatePasspointConfig(mWifiStateMachineChannel, config,
1217                Binder.getCallingUid());
1218    }
1219
1220    /**
1221     * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
1222     *
1223     * @param fqdn The FQDN of the Passpoint configuration to be removed
1224     * @return true on success or false on failure
1225     */
1226    @Override
1227    public boolean removePasspointConfiguration(String fqdn) {
1228        enforceChangePermission();
1229        mLog.trace("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1230        if (!mContext.getResources().getBoolean(
1231                com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
1232            throw new UnsupportedOperationException("Passpoint not enabled");
1233        }
1234        return mWifiStateMachine.syncRemovePasspointConfig(mWifiStateMachineChannel, fqdn);
1235    }
1236
1237    /**
1238     * Return the list of the installed Passpoint configurations.
1239     *
1240     * An empty list will be returned when no configuration is installed.
1241     *
1242     * @return A list of {@link PasspointConfiguration}
1243     */
1244    @Override
1245    public List<PasspointConfiguration> getPasspointConfigurations() {
1246        enforceAccessPermission();
1247        mLog.trace("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
1248        if (!mContext.getResources().getBoolean(
1249                com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
1250            throw new UnsupportedOperationException("Passpoint not enabled");
1251        }
1252        return mWifiStateMachine.syncGetPasspointConfigs(mWifiStateMachineChannel);
1253    }
1254
1255    /**
1256     * Query for a Hotspot 2.0 release 2 OSU icon
1257     * @param bssid The BSSID of the AP
1258     * @param fileName Icon file name
1259     */
1260    @Override
1261    public void queryPasspointIcon(long bssid, String fileName) {
1262        enforceAccessPermission();
1263        mLog.trace("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
1264        if (!mContext.getResources().getBoolean(
1265                com.android.internal.R.bool.config_wifi_hotspot2_enabled)) {
1266            throw new UnsupportedOperationException("Passpoint not enabled");
1267        }
1268        mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName);
1269    }
1270
1271    /**
1272     * Match the currently associated network against the SP matching the given FQDN
1273     * @param fqdn FQDN of the SP
1274     * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
1275     */
1276    @Override
1277    public int matchProviderWithCurrentNetwork(String fqdn) {
1278        mLog.trace("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
1279        return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
1280    }
1281
1282    /**
1283     * Deauthenticate and set the re-authentication hold off time for the current network
1284     * @param holdoff hold off time in milliseconds
1285     * @param ess set if the hold off pertains to an ESS rather than a BSS
1286     */
1287    @Override
1288    public void deauthenticateNetwork(long holdoff, boolean ess) {
1289        mLog.trace("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
1290        mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
1291    }
1292
1293    /**
1294     * Tell the supplicant to persist the current list of configured networks.
1295     * @return {@code true} if the operation succeeded
1296     *
1297     * TODO: deprecate this
1298     */
1299    @Override
1300    public boolean saveConfiguration() {
1301        enforceChangePermission();
1302        mLog.trace("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
1303        if (mWifiStateMachineChannel != null) {
1304            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1305        } else {
1306            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1307            return false;
1308        }
1309    }
1310
1311    /**
1312     * Set the country code
1313     * @param countryCode ISO 3166 country code.
1314     * @param persist {@code true} if the setting should be remembered.
1315     *
1316     * The persist behavior exists so that wifi can fall back to the last
1317     * persisted country code on a restart, when the locale information is
1318     * not available from telephony.
1319     */
1320    @Override
1321    public void setCountryCode(String countryCode, boolean persist) {
1322        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1323                " with persist set to " + persist);
1324        enforceConnectivityInternalPermission();
1325        mLog.trace("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
1326        final long token = Binder.clearCallingIdentity();
1327        mCountryCode.setCountryCode(countryCode);
1328        Binder.restoreCallingIdentity(token);
1329    }
1330
1331     /**
1332     * Get the country code
1333     * @return Get the best choice country code for wifi, regardless of if it was set or
1334     * not.
1335     * Returns null when there is no country code available.
1336     */
1337    @Override
1338    public String getCountryCode() {
1339        enforceConnectivityInternalPermission();
1340        mLog.trace("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
1341        String country = mCountryCode.getCountryCode();
1342        return country;
1343    }
1344
1345    @Override
1346    public boolean isDualBandSupported() {
1347        //TODO: Should move towards adding a driver API that checks at runtime
1348        mLog.trace("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
1349        return mContext.getResources().getBoolean(
1350                com.android.internal.R.bool.config_wifi_dual_band_support);
1351    }
1352
1353    /**
1354     * Return the DHCP-assigned addresses from the last successful DHCP request,
1355     * if any.
1356     * @return the DHCP information
1357     * @deprecated
1358     */
1359    @Override
1360    @Deprecated
1361    public DhcpInfo getDhcpInfo() {
1362        enforceAccessPermission();
1363        mLog.trace("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
1364        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1365
1366        DhcpInfo info = new DhcpInfo();
1367
1368        if (dhcpResults.ipAddress != null &&
1369                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1370            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1371        }
1372
1373        if (dhcpResults.gateway != null) {
1374            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1375        }
1376
1377        int dnsFound = 0;
1378        for (InetAddress dns : dhcpResults.dnsServers) {
1379            if (dns instanceof Inet4Address) {
1380                if (dnsFound == 0) {
1381                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1382                } else {
1383                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1384                }
1385                if (++dnsFound > 1) break;
1386            }
1387        }
1388        Inet4Address serverAddress = dhcpResults.serverAddress;
1389        if (serverAddress != null) {
1390            info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
1391        }
1392        info.leaseDuration = dhcpResults.leaseDuration;
1393
1394        return info;
1395    }
1396
1397    /**
1398     * enable TDLS for the local NIC to remote NIC
1399     * The APPs don't know the remote MAC address to identify NIC though,
1400     * so we need to do additional work to find it from remote IP address
1401     */
1402
1403    class TdlsTaskParams {
1404        public String remoteIpAddress;
1405        public boolean enable;
1406    }
1407
1408    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1409        @Override
1410        protected Integer doInBackground(TdlsTaskParams... params) {
1411
1412            // Retrieve parameters for the call
1413            TdlsTaskParams param = params[0];
1414            String remoteIpAddress = param.remoteIpAddress.trim();
1415            boolean enable = param.enable;
1416
1417            // Get MAC address of Remote IP
1418            String macAddress = null;
1419
1420            BufferedReader reader = null;
1421
1422            try {
1423                reader = new BufferedReader(new FileReader("/proc/net/arp"));
1424
1425                // Skip over the line bearing colum titles
1426                String line = reader.readLine();
1427
1428                while ((line = reader.readLine()) != null) {
1429                    String[] tokens = line.split("[ ]+");
1430                    if (tokens.length < 6) {
1431                        continue;
1432                    }
1433
1434                    // ARP column format is
1435                    // Address HWType HWAddress Flags Mask IFace
1436                    String ip = tokens[0];
1437                    String mac = tokens[3];
1438
1439                    if (remoteIpAddress.equals(ip)) {
1440                        macAddress = mac;
1441                        break;
1442                    }
1443                }
1444
1445                if (macAddress == null) {
1446                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
1447                            "/proc/net/arp");
1448                } else {
1449                    enableTdlsWithMacAddress(macAddress, enable);
1450                }
1451
1452            } catch (FileNotFoundException e) {
1453                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
1454            } catch (IOException e) {
1455                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
1456            } finally {
1457                try {
1458                    if (reader != null) {
1459                        reader.close();
1460                    }
1461                }
1462                catch (IOException e) {
1463                    // Do nothing
1464                }
1465            }
1466
1467            return 0;
1468        }
1469    }
1470
1471    @Override
1472    public void enableTdls(String remoteAddress, boolean enable) {
1473        if (remoteAddress == null) {
1474          throw new IllegalArgumentException("remoteAddress cannot be null");
1475        }
1476        mLog.trace("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
1477        TdlsTaskParams params = new TdlsTaskParams();
1478        params.remoteIpAddress = remoteAddress;
1479        params.enable = enable;
1480        new TdlsTask().execute(params);
1481    }
1482
1483
1484    @Override
1485    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
1486        mLog.trace("enableTdlsWithMacAddress uid=% enable=%")
1487                .c(Binder.getCallingUid())
1488                .c(enable)
1489                .flush();
1490        if (remoteMacAddress == null) {
1491          throw new IllegalArgumentException("remoteMacAddress cannot be null");
1492        }
1493
1494        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
1495    }
1496
1497    /**
1498     * Get a reference to handler. This is used by a client to establish
1499     * an AsyncChannel communication with WifiService
1500     */
1501    @Override
1502    public Messenger getWifiServiceMessenger() {
1503        enforceAccessPermission();
1504        enforceChangePermission();
1505        mLog.trace("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
1506        return new Messenger(mClientHandler);
1507    }
1508
1509    /**
1510     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
1511     */
1512    @Override
1513    public void disableEphemeralNetwork(String SSID) {
1514        enforceAccessPermission();
1515        enforceChangePermission();
1516        mLog.trace("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
1517        mWifiStateMachine.disableEphemeralNetwork(SSID);
1518    }
1519
1520    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1521        @Override
1522        public void onReceive(Context context, Intent intent) {
1523            String action = intent.getAction();
1524            if (action.equals(Intent.ACTION_SCREEN_ON)) {
1525                mWifiController.sendMessage(CMD_SCREEN_ON);
1526            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1527                mWifiController.sendMessage(CMD_USER_PRESENT);
1528            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1529                mWifiController.sendMessage(CMD_SCREEN_OFF);
1530            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1531                int pluggedType = intent.getIntExtra("plugged", 0);
1532                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
1533            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
1534                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
1535                        BluetoothAdapter.STATE_DISCONNECTED);
1536                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
1537            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
1538                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
1539                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
1540            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
1541                boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
1542                mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
1543            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
1544                handleIdleModeChanged();
1545            }
1546        }
1547    };
1548
1549    private boolean startConsentUi(String packageName,
1550            int callingUid, String intentAction) throws RemoteException {
1551        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
1552            return false;
1553        }
1554        try {
1555            // Validate the package only if we are going to use it
1556            ApplicationInfo applicationInfo = mContext.getPackageManager()
1557                    .getApplicationInfoAsUser(packageName,
1558                            PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
1559                            UserHandle.getUserId(callingUid));
1560            if (applicationInfo.uid != callingUid) {
1561                throw new SecurityException("Package " + callingUid
1562                        + " not in uid " + callingUid);
1563            }
1564
1565            // Permission review mode, trigger a user prompt
1566            Intent intent = new Intent(intentAction);
1567            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1568                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
1569            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
1570            mContext.startActivity(intent);
1571            return true;
1572        } catch (PackageManager.NameNotFoundException e) {
1573            throw new RemoteException(e.getMessage());
1574        }
1575    }
1576
1577    /**
1578     * Observes settings changes to scan always mode.
1579     */
1580    private void registerForScanModeChange() {
1581        ContentObserver contentObserver = new ContentObserver(null) {
1582            @Override
1583            public void onChange(boolean selfChange) {
1584                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
1585                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
1586            }
1587        };
1588        mFrameworkFacade.registerContentObserver(mContext,
1589                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
1590                false, contentObserver);
1591    }
1592
1593    private void registerForBroadcasts() {
1594        IntentFilter intentFilter = new IntentFilter();
1595        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
1596        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
1597        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
1598        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
1599        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
1600        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
1601        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
1602        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
1603
1604        boolean trackEmergencyCallState = mContext.getResources().getBoolean(
1605                com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
1606        if (trackEmergencyCallState) {
1607            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
1608        }
1609
1610        mContext.registerReceiver(mReceiver, intentFilter);
1611    }
1612
1613    private void registerForPackageOrUserRemoval() {
1614        IntentFilter intentFilter = new IntentFilter();
1615        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
1616        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
1617        mContext.registerReceiverAsUser(new BroadcastReceiver() {
1618            @Override
1619            public void onReceive(Context context, Intent intent) {
1620                switch (intent.getAction()) {
1621                    case Intent.ACTION_PACKAGE_REMOVED: {
1622                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
1623                            return;
1624                        }
1625                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1626                        Uri uri = intent.getData();
1627                        if (uid == -1 || uri == null) {
1628                            return;
1629                        }
1630                        String pkgName = uri.getSchemeSpecificPart();
1631                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
1632                        break;
1633                    }
1634                    case Intent.ACTION_USER_REMOVED: {
1635                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1636                        mWifiStateMachine.removeUserConfigs(userHandle);
1637                        break;
1638                    }
1639                }
1640            }
1641        }, UserHandle.ALL, intentFilter, null, null);
1642    }
1643
1644    @Override
1645    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1646        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1647                != PackageManager.PERMISSION_GRANTED) {
1648            pw.println("Permission Denial: can't dump WifiService from from pid="
1649                    + Binder.getCallingPid()
1650                    + ", uid=" + Binder.getCallingUid());
1651            return;
1652        }
1653        if (args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
1654            // WifiMetrics proto bytes were requested. Dump only these.
1655            mWifiStateMachine.updateWifiMetrics();
1656            mWifiMetrics.dump(fd, pw, args);
1657        } else if (args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
1658            // IpManager dump was requested. Pass it along and take no further action.
1659            String[] ipManagerArgs = new String[args.length - 1];
1660            System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
1661            mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
1662        } else if (args.length > 0 && DUMP_ARG_SET_IPREACH_DISCONNECT.equals(args[0])) {
1663            if (args.length > 1) {
1664                if (DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED.equals(args[1])) {
1665                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(true);
1666                } else if (DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED.equals(args[1])) {
1667                    mWifiStateMachine.setIpReachabilityDisconnectEnabled(false);
1668                }
1669            }
1670            pw.println("IPREACH_DISCONNECT state is "
1671                    + mWifiStateMachine.getIpReachabilityDisconnectEnabled());
1672            return;
1673        } else {
1674            pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
1675            pw.println("Stay-awake conditions: " +
1676                    Settings.Global.getInt(mContext.getContentResolver(),
1677                                           Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
1678            pw.println("mInIdleMode " + mInIdleMode);
1679            pw.println("mScanPending " + mScanPending);
1680            mWifiController.dump(fd, pw, args);
1681            mSettingsStore.dump(fd, pw, args);
1682            mTrafficPoller.dump(fd, pw, args);
1683            pw.println();
1684            pw.println("Locks held:");
1685            mWifiLockManager.dump(pw);
1686            pw.println();
1687            mWifiMulticastLockManager.dump(pw);
1688            pw.println();
1689            mWifiStateMachine.dump(fd, pw, args);
1690            pw.println();
1691            mWifiStateMachine.updateWifiMetrics();
1692            mWifiMetrics.dump(fd, pw, args);
1693            pw.println();
1694            mWifiBackupRestore.dump(fd, pw, args);
1695            pw.println();
1696        }
1697    }
1698
1699    @Override
1700    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
1701        mLog.trace("acquireWifiLock uid=% lockMode=%")
1702                .c(Binder.getCallingUid())
1703                .c(lockMode).flush();
1704        if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
1705            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1706            return true;
1707        }
1708        return false;
1709    }
1710
1711    @Override
1712    public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
1713        mLog.trace("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
1714        mWifiLockManager.updateWifiLockWorkSource(binder, ws);
1715    }
1716
1717    @Override
1718    public boolean releaseWifiLock(IBinder binder) {
1719        mLog.trace("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
1720        if (mWifiLockManager.releaseWifiLock(binder)) {
1721            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
1722            return true;
1723        }
1724        return false;
1725    }
1726
1727    @Override
1728    public void initializeMulticastFiltering() {
1729        enforceMulticastChangePermission();
1730        mLog.trace("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
1731        mWifiMulticastLockManager.initializeFiltering();
1732    }
1733
1734    @Override
1735    public void acquireMulticastLock(IBinder binder, String tag) {
1736        enforceMulticastChangePermission();
1737        mLog.trace("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
1738        mWifiMulticastLockManager.acquireLock(binder, tag);
1739    }
1740
1741    @Override
1742    public void releaseMulticastLock() {
1743        enforceMulticastChangePermission();
1744        mLog.trace("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
1745        mWifiMulticastLockManager.releaseLock();
1746    }
1747
1748    @Override
1749    public boolean isMulticastEnabled() {
1750        enforceAccessPermission();
1751        mLog.trace("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
1752        return mWifiMulticastLockManager.isMulticastEnabled();
1753    }
1754
1755    @Override
1756    public void enableVerboseLogging(int verbose) {
1757        enforceAccessPermission();
1758        mLog.trace("enableVerboseLogging uid=% verbose=%")
1759                .c(Binder.getCallingUid())
1760                .c(verbose).flush();
1761        mFacade.setIntegerSetting(
1762                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
1763        enableVerboseLoggingInternal(verbose);
1764    }
1765
1766    void enableVerboseLoggingInternal(int verbose) {
1767        mWifiStateMachine.enableVerboseLogging(verbose);
1768        mWifiLockManager.enableVerboseLogging(verbose);
1769        mWifiMulticastLockManager.enableVerboseLogging(verbose);
1770        mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
1771        mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
1772        LogcatLog.enableVerboseLogging(verbose);
1773    }
1774
1775    @Override
1776    public int getVerboseLoggingLevel() {
1777        enforceAccessPermission();
1778        mLog.trace("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
1779        return mFacade.getIntegerSetting(
1780                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
1781    }
1782
1783    @Override
1784    public void enableAggressiveHandover(int enabled) {
1785        enforceAccessPermission();
1786        mLog.trace("enableAggressiveHandover uid=% enabled=%")
1787            .c(Binder.getCallingUid())
1788            .c(enabled)
1789            .flush();
1790        mWifiStateMachine.enableAggressiveHandover(enabled);
1791    }
1792
1793    @Override
1794    public int getAggressiveHandover() {
1795        enforceAccessPermission();
1796        mLog.trace("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
1797        return mWifiStateMachine.getAggressiveHandover();
1798    }
1799
1800    @Override
1801    public void setAllowScansWithTraffic(int enabled) {
1802        enforceAccessPermission();
1803        mLog.trace("setAllowScansWithTraffic uid=% enabled=%")
1804                .c(Binder.getCallingUid())
1805                .c(enabled).flush();
1806        mWifiStateMachine.setAllowScansWithTraffic(enabled);
1807    }
1808
1809    @Override
1810    public int getAllowScansWithTraffic() {
1811        enforceAccessPermission();
1812        mLog.trace("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
1813        return mWifiStateMachine.getAllowScansWithTraffic();
1814    }
1815
1816    @Override
1817    public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
1818        enforceChangePermission();
1819        mLog.trace("setEnableAutoJoinWhenAssociated uid=% enabled=%")
1820                .c(Binder.getCallingUid())
1821                .c(enabled).flush();
1822        return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
1823    }
1824
1825    @Override
1826    public boolean getEnableAutoJoinWhenAssociated() {
1827        enforceAccessPermission();
1828        mLog.trace("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
1829        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
1830    }
1831
1832    /* Return the Wifi Connection statistics object */
1833    @Override
1834    public WifiConnectionStatistics getConnectionStatistics() {
1835        enforceAccessPermission();
1836        enforceReadCredentialPermission();
1837        mLog.trace("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
1838        if (mWifiStateMachineChannel != null) {
1839            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
1840        } else {
1841            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1842            return null;
1843        }
1844    }
1845
1846    @Override
1847    public void factoryReset() {
1848        enforceConnectivityInternalPermission();
1849        mLog.trace("factoryReset uid=%").c(Binder.getCallingUid()).flush();
1850        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
1851            return;
1852        }
1853
1854        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1855            // Turn mobile hotspot off
1856            setWifiApEnabled(null, false);
1857        }
1858
1859        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
1860            // Enable wifi
1861            try {
1862                setWifiEnabled(mContext.getOpPackageName(), true);
1863            } catch (RemoteException e) {
1864                /* ignore - local call */
1865            }
1866            // Delete all Wifi SSIDs
1867            if (mWifiStateMachineChannel != null) {
1868                List<WifiConfiguration> networks = mWifiStateMachine.syncGetConfiguredNetworks(
1869                        Binder.getCallingUid(), mWifiStateMachineChannel);
1870                if (networks != null) {
1871                    for (WifiConfiguration config : networks) {
1872                        removeNetwork(config.networkId);
1873                    }
1874                    saveConfiguration();
1875                }
1876            }
1877        }
1878    }
1879
1880    /* private methods */
1881    static boolean logAndReturnFalse(String s) {
1882        Log.d(TAG, s);
1883        return false;
1884    }
1885
1886    public static boolean isValid(WifiConfiguration config) {
1887        String validity = checkValidity(config);
1888        return validity == null || logAndReturnFalse(validity);
1889    }
1890
1891    public static boolean isValidPasspoint(WifiConfiguration config) {
1892        String validity = checkPasspointValidity(config);
1893        return validity == null || logAndReturnFalse(validity);
1894    }
1895
1896    public static String checkValidity(WifiConfiguration config) {
1897        if (config.allowedKeyManagement == null)
1898            return "allowed kmgmt";
1899
1900        if (config.allowedKeyManagement.cardinality() > 1) {
1901            if (config.allowedKeyManagement.cardinality() != 2) {
1902                return "cardinality != 2";
1903            }
1904            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
1905                return "not WPA_EAP";
1906            }
1907            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
1908                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
1909                return "not PSK or 8021X";
1910            }
1911        }
1912        if (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) {
1913            StaticIpConfiguration staticIpConf = config.getStaticIpConfiguration();
1914            if (staticIpConf == null) {
1915                return "null StaticIpConfiguration";
1916            }
1917            if (staticIpConf.ipAddress == null) {
1918                return "null static ip Address";
1919            }
1920        }
1921        return null;
1922    }
1923
1924    public static String checkPasspointValidity(WifiConfiguration config) {
1925        if (!TextUtils.isEmpty(config.FQDN)) {
1926            /* this is passpoint configuration; it must not have an SSID */
1927            if (!TextUtils.isEmpty(config.SSID)) {
1928                return "SSID not expected for Passpoint: '" + config.SSID +
1929                        "' FQDN " + toHexString(config.FQDN);
1930            }
1931            /* this is passpoint configuration; it must have a providerFriendlyName */
1932            if (TextUtils.isEmpty(config.providerFriendlyName)) {
1933                return "no provider friendly name";
1934            }
1935            WifiEnterpriseConfig enterpriseConfig = config.enterpriseConfig;
1936            /* this is passpoint configuration; it must have enterprise config */
1937            if (enterpriseConfig == null
1938                    || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
1939                return "no enterprise config";
1940            }
1941            if ((enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TLS ||
1942                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.TTLS ||
1943                    enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.PEAP) &&
1944                    enterpriseConfig.getCaCertificate() == null) {
1945                return "no CA certificate";
1946            }
1947        }
1948        return null;
1949    }
1950
1951    @Override
1952    public Network getCurrentNetwork() {
1953        enforceAccessPermission();
1954        mLog.trace("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
1955        return mWifiStateMachine.getCurrentNetwork();
1956    }
1957
1958    public static String toHexString(String s) {
1959        if (s == null) {
1960            return "null";
1961        }
1962        StringBuilder sb = new StringBuilder();
1963        sb.append('\'').append(s).append('\'');
1964        for (int n = 0; n < s.length(); n++) {
1965            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
1966        }
1967        return sb.toString();
1968    }
1969
1970    public void hideCertFromUnaffiliatedUsers(String alias) {
1971        mCertManager.hideCertFromUnaffiliatedUsers(alias);
1972    }
1973
1974    public String[] listClientCertsForCurrentUser() {
1975        return mCertManager.listClientCertsForCurrentUser();
1976    }
1977
1978    /**
1979     * Enable/disable WifiConnectivityManager at runtime
1980     *
1981     * @param enabled true-enable; false-disable
1982     */
1983    @Override
1984    public void enableWifiConnectivityManager(boolean enabled) {
1985        enforceConnectivityInternalPermission();
1986        mLog.trace("enableWifiConnectivityManager uid=% enabled=%")
1987            .c(Binder.getCallingUid())
1988            .c(enabled).flush();
1989        mWifiStateMachine.enableWifiConnectivityManager(enabled);
1990    }
1991
1992    /**
1993     * Retrieve the data to be backed to save the current state.
1994     *
1995     * @return  Raw byte stream of the data to be backed up.
1996     */
1997    @Override
1998    public byte[] retrieveBackupData() {
1999        enforceReadCredentialPermission();
2000        enforceAccessPermission();
2001        mLog.trace("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
2002        if (mWifiStateMachineChannel == null) {
2003            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2004            return null;
2005        }
2006
2007        Slog.d(TAG, "Retrieving backup data");
2008        List<WifiConfiguration> wifiConfigurations =
2009                mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
2010        byte[] backupData =
2011                mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
2012        Slog.d(TAG, "Retrieved backup data");
2013        return backupData;
2014    }
2015
2016    /**
2017     * Helper method to restore networks retrieved from backup data.
2018     *
2019     * @param configurations list of WifiConfiguration objects parsed from the backup data.
2020     */
2021    private void restoreNetworks(List<WifiConfiguration> configurations) {
2022        if (configurations == null) {
2023            Slog.e(TAG, "Backup data parse failed");
2024            return;
2025        }
2026        for (WifiConfiguration configuration : configurations) {
2027            int networkId = mWifiStateMachine.syncAddOrUpdateNetwork(
2028                    mWifiStateMachineChannel, configuration);
2029            if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
2030                Slog.e(TAG, "Restore network failed: " + configuration.configKey());
2031                continue;
2032            }
2033            // Enable all networks restored.
2034            mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
2035        }
2036    }
2037
2038    /**
2039     * Restore state from the backed up data.
2040     *
2041     * @param data Raw byte stream of the backed up data.
2042     */
2043    @Override
2044    public void restoreBackupData(byte[] data) {
2045        enforceChangePermission();
2046        mLog.trace("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
2047        if (mWifiStateMachineChannel == null) {
2048            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2049            return;
2050        }
2051
2052        Slog.d(TAG, "Restoring backup data");
2053        List<WifiConfiguration> wifiConfigurations =
2054                mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
2055        restoreNetworks(wifiConfigurations);
2056        Slog.d(TAG, "Restored backup data");
2057    }
2058
2059    /**
2060     * Restore state from the older supplicant back up data.
2061     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
2062     *
2063     * @param supplicantData Raw byte stream of wpa_supplicant.conf
2064     * @param ipConfigData Raw byte stream of ipconfig.txt
2065     */
2066    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
2067        enforceChangePermission();
2068        mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
2069        if (mWifiStateMachineChannel == null) {
2070            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2071            return;
2072        }
2073
2074        Slog.d(TAG, "Restoring supplicant backup data");
2075        List<WifiConfiguration> wifiConfigurations =
2076                mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
2077                        supplicantData, ipConfigData);
2078        restoreNetworks(wifiConfigurations);
2079        Slog.d(TAG, "Restored supplicant backup data");
2080    }
2081}
2082