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