WifiServiceImpl.java revision 470817b13e56d915805729ab4f51075f3fa2ec15
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 android.net.wifi.WifiManager.EXTRA_PREVIOUS_WIFI_AP_STATE;
20import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_FAILURE_REASON;
21import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
22import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
23import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
24import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
25import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
26import static android.net.wifi.WifiManager.SAP_START_FAILURE_NO_CHANNEL;
27import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
28import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
29import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
30
31import static com.android.server.wifi.LocalOnlyHotspotRequestInfo.HOTSPOT_NO_ERROR;
32import static com.android.server.wifi.WifiController.CMD_AIRPLANE_TOGGLED;
33import static com.android.server.wifi.WifiController.CMD_BATTERY_CHANGED;
34import static com.android.server.wifi.WifiController.CMD_EMERGENCY_CALL_STATE_CHANGED;
35import static com.android.server.wifi.WifiController.CMD_EMERGENCY_MODE_CHANGED;
36import static com.android.server.wifi.WifiController.CMD_LOCKS_CHANGED;
37import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGED;
38import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF;
39import static com.android.server.wifi.WifiController.CMD_SCREEN_ON;
40import static com.android.server.wifi.WifiController.CMD_SET_AP;
41import static com.android.server.wifi.WifiController.CMD_USER_PRESENT;
42import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
43
44import android.Manifest;
45import android.app.ActivityManager;
46import android.app.ActivityManager.RunningAppProcessInfo;
47import android.app.AppOpsManager;
48import android.bluetooth.BluetoothAdapter;
49import android.content.BroadcastReceiver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
53import android.content.pm.ApplicationInfo;
54import android.content.pm.PackageManager;
55import android.content.pm.ParceledListSlice;
56import android.database.ContentObserver;
57import android.net.DhcpInfo;
58import android.net.DhcpResults;
59import android.net.IpConfiguration;
60import android.net.Network;
61import android.net.NetworkUtils;
62import android.net.StaticIpConfiguration;
63import android.net.Uri;
64import android.net.ip.IpManager;
65import android.net.wifi.IWifiManager;
66import android.net.wifi.ScanResult;
67import android.net.wifi.ScanSettings;
68import android.net.wifi.WifiActivityEnergyInfo;
69import android.net.wifi.WifiConfiguration;
70import android.net.wifi.WifiConnectionStatistics;
71import android.net.wifi.WifiInfo;
72import android.net.wifi.WifiLinkLayerStats;
73import android.net.wifi.WifiManager;
74import android.net.wifi.WifiManager.LocalOnlyHotspotCallback;
75import android.net.wifi.WifiScanner;
76import android.net.wifi.hotspot2.OsuProvider;
77import android.net.wifi.hotspot2.PasspointConfiguration;
78import android.os.AsyncTask;
79import android.os.BatteryStats;
80import android.os.Binder;
81import android.os.Build;
82import android.os.Bundle;
83import android.os.HandlerThread;
84import android.os.IBinder;
85import android.os.Looper;
86import android.os.Message;
87import android.os.Messenger;
88import android.os.PowerManager;
89import android.os.Process;
90import android.os.RemoteException;
91import android.os.ResultReceiver;
92import android.os.ShellCallback;
93import android.os.UserHandle;
94import android.os.UserManager;
95import android.os.WorkSource;
96import android.provider.Settings;
97import android.util.ArrayMap;
98import android.util.ArraySet;
99import android.util.Log;
100import android.util.Slog;
101
102import com.android.internal.annotations.GuardedBy;
103import com.android.internal.annotations.VisibleForTesting;
104import com.android.internal.telephony.IccCardConstants;
105import com.android.internal.telephony.PhoneConstants;
106import com.android.internal.telephony.TelephonyIntents;
107import com.android.internal.util.AsyncChannel;
108import com.android.server.wifi.hotspot2.PasspointProvider;
109import com.android.server.wifi.util.WifiHandler;
110import com.android.server.wifi.util.WifiPermissionsUtil;
111
112import java.io.BufferedReader;
113import java.io.FileDescriptor;
114import java.io.FileNotFoundException;
115import java.io.FileReader;
116import java.io.IOException;
117import java.io.PrintWriter;
118import java.net.Inet4Address;
119import java.net.InetAddress;
120import java.security.GeneralSecurityException;
121import java.security.KeyStore;
122import java.security.cert.CertPath;
123import java.security.cert.CertPathValidator;
124import java.security.cert.CertificateFactory;
125import java.security.cert.PKIXParameters;
126import java.security.cert.X509Certificate;
127import java.util.ArrayList;
128import java.util.Arrays;
129import java.util.HashMap;
130import java.util.List;
131import java.util.concurrent.ConcurrentHashMap;
132
133/**
134 * WifiService handles remote WiFi operation requests by implementing
135 * the IWifiManager interface.
136 *
137 * @hide
138 */
139public class WifiServiceImpl extends IWifiManager.Stub {
140    private static final String TAG = "WifiService";
141    private static final boolean DBG = true;
142    private static final boolean VDBG = false;
143
144    // Dumpsys argument to enable/disable disconnect on IP reachability failures.
145    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT = "set-ipreach-disconnect";
146    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_ENABLED = "enabled";
147    private static final String DUMP_ARG_SET_IPREACH_DISCONNECT_DISABLED = "disabled";
148
149    // Default scan background throttling interval if not overriden in settings
150    private static final long DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS = 30 * 60 * 1000;
151
152    // Apps with importance higher than this value is considered as background app.
153    private static final int BACKGROUND_IMPORTANCE_CUTOFF =
154            RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
155
156    final WifiStateMachine mWifiStateMachine;
157
158    private final Context mContext;
159    private final FrameworkFacade mFacade;
160    private final Clock mClock;
161    private final ArraySet<String> mBackgroundThrottlePackageWhitelist = new ArraySet<>();
162
163    private final PowerManager mPowerManager;
164    private final AppOpsManager mAppOps;
165    private final UserManager mUserManager;
166    private final ActivityManager mActivityManager;
167    private final WifiCountryCode mCountryCode;
168    private long mBackgroundThrottleInterval;
169    // Debug counter tracking scan requests sent by WifiManager
170    private int scanRequestCounter = 0;
171
172    /* Polls traffic stats and notifies clients */
173    private WifiTrafficPoller mTrafficPoller;
174    /* Tracks the persisted states for wi-fi & airplane mode */
175    final WifiSettingsStore mSettingsStore;
176    /* Logs connection events and some general router and scan stats */
177    private final WifiMetrics mWifiMetrics;
178    /* Manages affiliated certificates for current user */
179    private final WifiCertManager mCertManager;
180
181    private final WifiInjector mWifiInjector;
182    /* Backup/Restore Module */
183    private final WifiBackupRestore mWifiBackupRestore;
184
185    // Map of package name of background scan apps and last scan timestamp.
186    private final ArrayMap<String, Long> mLastScanTimestamps;
187
188    private WifiScanner mWifiScanner;
189    private WifiLog mLog;
190
191    /**
192     * Asynchronous channel to WifiStateMachine
193     */
194    private AsyncChannel mWifiStateMachineChannel;
195
196    private final boolean mPermissionReviewRequired;
197    private final FrameworkFacade mFrameworkFacade;
198
199    private WifiPermissionsUtil mWifiPermissionsUtil;
200
201    @GuardedBy("mLocalOnlyHotspotRequests")
202    private final HashMap<Integer, LocalOnlyHotspotRequestInfo> mLocalOnlyHotspotRequests;
203    @GuardedBy("mLocalOnlyHotspotRequests")
204    private WifiConfiguration mLocalOnlyHotspotConfig = null;
205    @GuardedBy("mLocalOnlyHotspotRequests")
206    private final ConcurrentHashMap<String, Integer> mIfaceIpModes;
207
208    /**
209     * Callback for use with LocalOnlyHotspot to unregister requesting applications upon death.
210     *
211     * @hide
212     */
213    public final class LocalOnlyRequestorCallback
214            implements LocalOnlyHotspotRequestInfo.RequestingApplicationDeathCallback {
215        /**
216         * Called with requesting app has died.
217         */
218        @Override
219        public void onLocalOnlyHotspotRequestorDeath(LocalOnlyHotspotRequestInfo requestor) {
220            unregisterCallingAppAndStopLocalOnlyHotspot(requestor);
221        };
222    }
223
224    /**
225     * Handles client connections
226     */
227    private class ClientHandler extends WifiHandler {
228
229        ClientHandler(String tag, Looper looper) {
230            super(tag, looper);
231        }
232
233        @Override
234        public void handleMessage(Message msg) {
235            super.handleMessage(msg);
236            switch (msg.what) {
237                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
238                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
239                        if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
240                        // We track the clients by the Messenger
241                        // since it is expected to be always available
242                        mTrafficPoller.addClient(msg.replyTo);
243                    } else {
244                        Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
245                    }
246                    break;
247                }
248                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
249                    if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) {
250                        if (DBG) Slog.d(TAG, "Send failed, client connection lost");
251                    } else {
252                        if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
253                    }
254                    mTrafficPoller.removeClient(msg.replyTo);
255                    break;
256                }
257                case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
258                    AsyncChannel ac = mFrameworkFacade.makeWifiAsyncChannel(TAG);
259                    ac.connect(mContext, this, msg.replyTo);
260                    break;
261                }
262                case WifiManager.CONNECT_NETWORK: {
263                    if (checkChangePermissionAndReplyIfNotAuthorized(
264                            msg, WifiManager.CONNECT_NETWORK_FAILED)) {
265                        WifiConfiguration config = (WifiConfiguration) msg.obj;
266                        int networkId = msg.arg1;
267                        Slog.d(TAG, "CONNECT "
268                                + " nid=" + Integer.toString(networkId)
269                                + " uid=" + msg.sendingUid
270                                + " name="
271                                + mContext.getPackageManager().getNameForUid(msg.sendingUid));
272                        if (config != null) {
273                            if (DBG) Slog.d(TAG, "Connect with config " + config);
274                            /* Command is forwarded to state machine */
275                            mWifiStateMachine.sendMessage(Message.obtain(msg));
276                        } else if (config == null
277                                && networkId != WifiConfiguration.INVALID_NETWORK_ID) {
278                            if (DBG) Slog.d(TAG, "Connect with networkId " + networkId);
279                            mWifiStateMachine.sendMessage(Message.obtain(msg));
280                        } else {
281                            Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
282                            replyFailed(msg, WifiManager.CONNECT_NETWORK_FAILED,
283                                    WifiManager.INVALID_ARGS);
284                        }
285                    }
286                    break;
287                }
288                case WifiManager.SAVE_NETWORK: {
289                    if (checkChangePermissionAndReplyIfNotAuthorized(
290                            msg, WifiManager.SAVE_NETWORK_FAILED)) {
291                        WifiConfiguration config = (WifiConfiguration) msg.obj;
292                        int networkId = msg.arg1;
293                        Slog.d(TAG, "SAVE"
294                                + " nid=" + Integer.toString(networkId)
295                                + " uid=" + msg.sendingUid
296                                + " name="
297                                + mContext.getPackageManager().getNameForUid(msg.sendingUid));
298                        if (config != null) {
299                            if (DBG) Slog.d(TAG, "Save network with config " + config);
300                            /* Command is forwarded to state machine */
301                            mWifiStateMachine.sendMessage(Message.obtain(msg));
302                        } else {
303                            Slog.e(TAG, "ClientHandler.handleMessage ignoring invalid msg=" + msg);
304                            replyFailed(msg, WifiManager.SAVE_NETWORK_FAILED,
305                                    WifiManager.INVALID_ARGS);
306                        }
307                    }
308                    break;
309                }
310                case WifiManager.FORGET_NETWORK:
311                    if (checkChangePermissionAndReplyIfNotAuthorized(
312                            msg, WifiManager.FORGET_NETWORK_FAILED)) {
313                        mWifiStateMachine.sendMessage(Message.obtain(msg));
314                    }
315                    break;
316                case WifiManager.START_WPS:
317                    if (checkChangePermissionAndReplyIfNotAuthorized(msg, WifiManager.WPS_FAILED)) {
318                        mWifiStateMachine.sendMessage(Message.obtain(msg));
319                    }
320                    break;
321                case WifiManager.CANCEL_WPS:
322                    if (checkChangePermissionAndReplyIfNotAuthorized(
323                            msg, WifiManager.CANCEL_WPS_FAILED)) {
324                        mWifiStateMachine.sendMessage(Message.obtain(msg));
325                    }
326                    break;
327                case WifiManager.DISABLE_NETWORK:
328                    if (checkChangePermissionAndReplyIfNotAuthorized(
329                            msg, WifiManager.DISABLE_NETWORK_FAILED)) {
330                        mWifiStateMachine.sendMessage(Message.obtain(msg));
331                    }
332                    break;
333                case WifiManager.RSSI_PKTCNT_FETCH: {
334                    if (checkChangePermissionAndReplyIfNotAuthorized(
335                            msg, WifiManager.RSSI_PKTCNT_FETCH_FAILED)) {
336                        mWifiStateMachine.sendMessage(Message.obtain(msg));
337                    }
338                    break;
339                }
340                default: {
341                    Slog.d(TAG, "ClientHandler.handleMessage ignoring msg=" + msg);
342                    break;
343                }
344            }
345        }
346
347        /**
348         * Helper method to check if the sender of the message holds the
349         * {@link Manifest.permission#CHANGE_WIFI_STATE} permission, and reply with a failure if it
350         * doesn't
351         *
352         * @param msg Incoming message.
353         * @param replyWhat Param to be filled in the {@link Message#what} field of the failure
354         *                  reply.
355         * @return true if the sender holds the permission, false otherwise.
356         */
357        private boolean checkChangePermissionAndReplyIfNotAuthorized(Message msg, int replyWhat) {
358            if (!mWifiPermissionsUtil.checkChangePermission(msg.sendingUid)) {
359                Slog.e(TAG, "ClientHandler.handleMessage ignoring unauthorized msg=" + msg);
360                replyFailed(msg, replyWhat, WifiManager.NOT_AUTHORIZED);
361                return false;
362            }
363            return true;
364        }
365
366        private void replyFailed(Message msg, int what, int why) {
367            if (msg.replyTo == null) return;
368            Message reply = Message.obtain();
369            reply.what = what;
370            reply.arg1 = why;
371            try {
372                msg.replyTo.send(reply);
373            } catch (RemoteException e) {
374                // There's not much we can do if reply can't be sent!
375            }
376        }
377    }
378    private ClientHandler mClientHandler;
379
380    /**
381     * Handles interaction with WifiStateMachine
382     */
383    private class WifiStateMachineHandler extends WifiHandler {
384        private AsyncChannel mWsmChannel;
385
386        WifiStateMachineHandler(String tag, Looper looper, AsyncChannel asyncChannel) {
387            super(tag, looper);
388            mWsmChannel = asyncChannel;
389            mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
390        }
391
392        @Override
393        public void handleMessage(Message msg) {
394            super.handleMessage(msg);
395            switch (msg.what) {
396                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
397                    if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
398                        mWifiStateMachineChannel = mWsmChannel;
399                    } else {
400                        Slog.e(TAG, "WifiStateMachine connection failure, error=" + msg.arg1);
401                        mWifiStateMachineChannel = null;
402                    }
403                    break;
404                }
405                case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
406                    Slog.e(TAG, "WifiStateMachine channel lost, msg.arg1 =" + msg.arg1);
407                    mWifiStateMachineChannel = null;
408                    //Re-establish connection to state machine
409                    mWsmChannel.connect(mContext, this, mWifiStateMachine.getHandler());
410                    break;
411                }
412                default: {
413                    Slog.d(TAG, "WifiStateMachineHandler.handleMessage ignoring msg=" + msg);
414                    break;
415                }
416            }
417        }
418    }
419
420    WifiStateMachineHandler mWifiStateMachineHandler;
421    private WifiController mWifiController;
422    private final WifiLockManager mWifiLockManager;
423    private final WifiMulticastLockManager mWifiMulticastLockManager;
424
425    public WifiServiceImpl(Context context, WifiInjector wifiInjector, AsyncChannel asyncChannel) {
426        mContext = context;
427        mWifiInjector = wifiInjector;
428        mClock = wifiInjector.getClock();
429
430        mFacade = mWifiInjector.getFrameworkFacade();
431        mWifiMetrics = mWifiInjector.getWifiMetrics();
432        mTrafficPoller = mWifiInjector.getWifiTrafficPoller();
433        mUserManager = mWifiInjector.getUserManager();
434        mCountryCode = mWifiInjector.getWifiCountryCode();
435        mWifiStateMachine = mWifiInjector.getWifiStateMachine();
436        mWifiStateMachine.enableRssiPolling(true);
437        mSettingsStore = mWifiInjector.getWifiSettingsStore();
438        mPowerManager = mContext.getSystemService(PowerManager.class);
439        mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
440        mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
441        mCertManager = mWifiInjector.getWifiCertManager();
442        mWifiLockManager = mWifiInjector.getWifiLockManager();
443        mWifiMulticastLockManager = mWifiInjector.getWifiMulticastLockManager();
444        HandlerThread wifiServiceHandlerThread = mWifiInjector.getWifiServiceHandlerThread();
445        mClientHandler = new ClientHandler(TAG, wifiServiceHandlerThread.getLooper());
446        mWifiStateMachineHandler = new WifiStateMachineHandler(TAG,
447                wifiServiceHandlerThread.getLooper(), asyncChannel);
448        mWifiController = mWifiInjector.getWifiController();
449        mWifiBackupRestore = mWifiInjector.getWifiBackupRestore();
450        mPermissionReviewRequired = Build.PERMISSIONS_REVIEW_REQUIRED
451                || context.getResources().getBoolean(
452                com.android.internal.R.bool.config_permissionReviewRequired);
453        mWifiPermissionsUtil = mWifiInjector.getWifiPermissionsUtil();
454        mLog = mWifiInjector.makeLog(TAG);
455        mFrameworkFacade = wifiInjector.getFrameworkFacade();
456        mLastScanTimestamps = new ArrayMap<>();
457        updateBackgroundThrottleInterval();
458        updateBackgroundThrottlingWhitelist();
459        mIfaceIpModes = new ConcurrentHashMap<>();
460        mLocalOnlyHotspotRequests = new HashMap<>();
461        enableVerboseLoggingInternal(getVerboseLoggingLevel());
462    }
463
464    /**
465     * Provide a way for unit tests to set valid log object in the WifiHandler
466     * @param log WifiLog object to assign to the clientHandler
467     */
468    @VisibleForTesting
469    public void setWifiHandlerLogForTest(WifiLog log) {
470        mClientHandler.setWifiLog(log);
471    }
472
473    /**
474     * Check if we are ready to start wifi.
475     *
476     * First check if we will be restarting system services to decrypt the device. If the device is
477     * not encrypted, check if Wi-Fi needs to be enabled and start if needed
478     *
479     * This function is used only at boot time.
480     */
481    public void checkAndStartWifi() {
482        // First check if we will end up restarting WifiService
483        if (mFrameworkFacade.inStorageManagerCryptKeeperBounce()) {
484            Log.d(TAG, "Device still encrypted. Need to restart SystemServer.  Do not start wifi.");
485            return;
486        }
487
488        // Check if wi-fi needs to be enabled
489        boolean wifiEnabled = mSettingsStore.isWifiToggleEnabled();
490        Slog.i(TAG, "WifiService starting up with Wi-Fi " +
491                (wifiEnabled ? "enabled" : "disabled"));
492
493        registerForScanModeChange();
494        registerForBackgroundThrottleChanges();
495        mContext.registerReceiver(
496                new BroadcastReceiver() {
497                    @Override
498                    public void onReceive(Context context, Intent intent) {
499                        if (mSettingsStore.handleAirplaneModeToggled()) {
500                            mWifiController.sendMessage(CMD_AIRPLANE_TOGGLED);
501                        }
502                        if (mSettingsStore.isAirplaneModeOn()) {
503                            Log.d(TAG, "resetting country code because Airplane mode is ON");
504                            mCountryCode.airplaneModeEnabled();
505                        }
506                    }
507                },
508                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
509
510        mContext.registerReceiver(
511                new BroadcastReceiver() {
512                    @Override
513                    public void onReceive(Context context, Intent intent) {
514                        String state = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
515                        if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(state)) {
516                            Log.d(TAG, "resetting networks because SIM was removed");
517                            mWifiStateMachine.resetSimAuthNetworks(false);
518                            Log.d(TAG, "resetting country code because SIM is removed");
519                            mCountryCode.simCardRemoved();
520                        } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(state)) {
521                            Log.d(TAG, "resetting networks because SIM was loaded");
522                            mWifiStateMachine.resetSimAuthNetworks(true);
523                        }
524                    }
525                },
526                new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
527
528        mContext.registerReceiver(
529                new BroadcastReceiver() {
530                    @Override
531                    public void onReceive(Context context, Intent intent) {
532                        final int currState = intent.getIntExtra(EXTRA_WIFI_AP_STATE,
533                                                                    WIFI_AP_STATE_DISABLED);
534                        final int prevState = intent.getIntExtra(EXTRA_PREVIOUS_WIFI_AP_STATE,
535                                                                 WIFI_AP_STATE_DISABLED);
536                        final int errorCode = intent.getIntExtra(EXTRA_WIFI_AP_FAILURE_REASON,
537                                                                 HOTSPOT_NO_ERROR);
538                        final String ifaceName =
539                                intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
540                        final int mode = intent.getIntExtra(EXTRA_WIFI_AP_MODE,
541                                                            WifiManager.IFACE_IP_MODE_UNSPECIFIED);
542                        handleWifiApStateChange(currState, prevState, errorCode, ifaceName, mode);
543                    }
544                },
545                new IntentFilter(WifiManager.WIFI_AP_STATE_CHANGED_ACTION));
546
547        // Adding optimizations of only receiving broadcasts when wifi is enabled
548        // can result in race conditions when apps toggle wifi in the background
549        // without active user involvement. Always receive broadcasts.
550        registerForBroadcasts();
551        registerForPackageOrUserRemoval();
552        mInIdleMode = mPowerManager.isDeviceIdleMode();
553
554        if (!mWifiStateMachine.syncInitialize(mWifiStateMachineChannel)) {
555            Log.wtf(TAG, "Failed to initialize WifiStateMachine");
556        }
557        mWifiController.start();
558
559        // If we are already disabled (could be due to airplane mode), avoid changing persist
560        // state here
561        if (wifiEnabled) {
562            try {
563                setWifiEnabled(mContext.getPackageName(), wifiEnabled);
564            } catch (RemoteException e) {
565                /* ignore - local call */
566            }
567        }
568    }
569
570    public void handleUserSwitch(int userId) {
571        mWifiStateMachine.handleUserSwitch(userId);
572    }
573
574    public void handleUserUnlock(int userId) {
575        mWifiStateMachine.handleUserUnlock(userId);
576    }
577
578    public void handleUserStop(int userId) {
579        mWifiStateMachine.handleUserStop(userId);
580    }
581
582    /**
583     * see {@link android.net.wifi.WifiManager#startScan}
584     * and {@link android.net.wifi.WifiManager#startCustomizedScan}
585     *
586     * @param settings If null, use default parameter, i.e. full scan.
587     * @param workSource If null, all blame is given to the calling uid.
588     * @param packageName Package name of the app that requests wifi scan.
589     */
590    @Override
591    public void startScan(ScanSettings settings, WorkSource workSource, String packageName) {
592        enforceChangePermission();
593
594        mLog.info("startScan uid=%").c(Binder.getCallingUid()).flush();
595        // Check and throttle background apps for wifi scan.
596        if (isRequestFromBackground(packageName)) {
597            long lastScanMs = mLastScanTimestamps.getOrDefault(packageName, 0L);
598            long elapsedRealtime = mClock.getElapsedSinceBootMillis();
599
600            if (lastScanMs != 0 && (elapsedRealtime - lastScanMs) < mBackgroundThrottleInterval) {
601                sendFailedScanBroadcast();
602                return;
603            }
604            // Proceed with the scan request and record the time.
605            mLastScanTimestamps.put(packageName, elapsedRealtime);
606        }
607        synchronized (this) {
608            if (mWifiScanner == null) {
609                mWifiScanner = mWifiInjector.getWifiScanner();
610            }
611            if (mInIdleMode) {
612                // Need to send an immediate scan result broadcast in case the
613                // caller is waiting for a result ..
614
615                // TODO: investigate if the logic to cancel scans when idle can move to
616                // WifiScanningServiceImpl.  This will 1 - clean up WifiServiceImpl and 2 -
617                // avoid plumbing an awkward path to report a cancelled/failed scan.  This will
618                // be sent directly until b/31398592 is fixed.
619                sendFailedScanBroadcast();
620                mScanPending = true;
621                return;
622            }
623        }
624        if (settings != null) {
625            settings = new ScanSettings(settings);
626            if (!settings.isValid()) {
627                Slog.e(TAG, "invalid scan setting");
628                return;
629            }
630        }
631        if (workSource != null) {
632            enforceWorkSourcePermission();
633            // WifiManager currently doesn't use names, so need to clear names out of the
634            // supplied WorkSource to allow future WorkSource combining.
635            workSource.clearNames();
636        }
637        if (workSource == null && Binder.getCallingUid() >= 0) {
638            workSource = new WorkSource(Binder.getCallingUid());
639        }
640        mWifiStateMachine.startScan(Binder.getCallingUid(), scanRequestCounter++,
641                settings, workSource);
642    }
643
644    // Send a failed scan broadcast to indicate the current scan request failed.
645    private void sendFailedScanBroadcast() {
646        // clear calling identity to send broadcast
647        long callingIdentity = Binder.clearCallingIdentity();
648        try {
649            Intent intent = new Intent(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
650            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
651            intent.putExtra(WifiManager.EXTRA_RESULTS_UPDATED, false);
652            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
653        } finally {
654            // restore calling identity
655            Binder.restoreCallingIdentity(callingIdentity);
656        }
657
658    }
659
660    // Check if the request comes from background.
661    private boolean isRequestFromBackground(String packageName) {
662        // Requests from system or wifi are not background.
663        if (Binder.getCallingUid() == Process.SYSTEM_UID
664                || Binder.getCallingUid() == Process.WIFI_UID) {
665            return false;
666        }
667        mAppOps.checkPackage(Binder.getCallingUid(), packageName);
668        if (mBackgroundThrottlePackageWhitelist.contains(packageName)) {
669            return false;
670        }
671
672        // getPackageImportance requires PACKAGE_USAGE_STATS permission, so clearing the incoming
673        // identify so the permission check can be done on system process where wifi runs in.
674        long callingIdentity = Binder.clearCallingIdentity();
675        try {
676            return mActivityManager.getPackageImportance(packageName)
677                    > BACKGROUND_IMPORTANCE_CUTOFF;
678        } finally {
679            Binder.restoreCallingIdentity(callingIdentity);
680        }
681    }
682
683    @Override
684    public String getCurrentNetworkWpsNfcConfigurationToken() {
685        enforceConnectivityInternalPermission();
686        mLog.info("getCurrentNetworkWpsNfcConfigurationToken uid=%")
687                .c(Binder.getCallingUid()).flush();
688        // TODO Add private logging for netId b/33807876
689        return mWifiStateMachine.syncGetCurrentNetworkWpsNfcConfigurationToken();
690    }
691
692    boolean mInIdleMode;
693    boolean mScanPending;
694
695    void handleIdleModeChanged() {
696        boolean doScan = false;
697        synchronized (this) {
698            boolean idle = mPowerManager.isDeviceIdleMode();
699            if (mInIdleMode != idle) {
700                mInIdleMode = idle;
701                if (!idle) {
702                    if (mScanPending) {
703                        mScanPending = false;
704                        doScan = true;
705                    }
706                }
707            }
708        }
709        if (doScan) {
710            // Someone requested a scan while we were idle; do a full scan now.
711            // The package name doesn't matter as the request comes from System UID.
712            startScan(null, null, "");
713        }
714    }
715
716    private boolean checkNetworkSettingsPermission(int pid, int uid) {
717        return mContext.checkPermission(android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
718                == PackageManager.PERMISSION_GRANTED;
719    }
720
721    private void enforceNetworkSettingsPermission() {
722        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_SETTINGS,
723                "WifiService");
724    }
725
726    private void enforceNetworkStackPermission() {
727        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK,
728                "WifiService");
729    }
730
731    private void enforceAccessPermission() {
732        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
733                "WifiService");
734    }
735
736    private void enforceChangePermission() {
737        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CHANGE_WIFI_STATE,
738                "WifiService");
739    }
740
741    private void enforceLocationHardwarePermission() {
742        mContext.enforceCallingOrSelfPermission(Manifest.permission.LOCATION_HARDWARE,
743                "LocationHardware");
744    }
745
746    private void enforceReadCredentialPermission() {
747        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_WIFI_CREDENTIAL,
748                                                "WifiService");
749    }
750
751    private void enforceWorkSourcePermission() {
752        mContext.enforceCallingPermission(android.Manifest.permission.UPDATE_DEVICE_STATS,
753                "WifiService");
754
755    }
756
757    private void enforceMulticastChangePermission() {
758        mContext.enforceCallingOrSelfPermission(
759                android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE,
760                "WifiService");
761    }
762
763    private void enforceConnectivityInternalPermission() {
764        mContext.enforceCallingOrSelfPermission(
765                android.Manifest.permission.CONNECTIVITY_INTERNAL,
766                "ConnectivityService");
767    }
768
769    private void enforceLocationPermission(String pkgName, int uid) {
770        mWifiPermissionsUtil.enforceLocationPermission(pkgName, uid);
771    }
772
773    /**
774     * see {@link android.net.wifi.WifiManager#setWifiEnabled(boolean)}
775     * @param enable {@code true} to enable, {@code false} to disable.
776     * @return {@code true} if the enable/disable operation was
777     *         started or is already in the queue.
778     */
779    @Override
780    public synchronized boolean setWifiEnabled(String packageName, boolean enable)
781            throws RemoteException {
782        enforceChangePermission();
783        Slog.d(TAG, "setWifiEnabled: " + enable + " pid=" + Binder.getCallingPid()
784                    + ", uid=" + Binder.getCallingUid() + ", package=" + packageName);
785        mLog.info("setWifiEnabled package=% uid=% enable=%").c(packageName)
786                .c(Binder.getCallingUid()).c(enable).flush();
787
788        boolean isFromSettings = checkNetworkSettingsPermission(
789                Binder.getCallingPid(), Binder.getCallingUid());
790
791        // If Airplane mode is enabled, only Settings is allowed to toggle Wifi
792        if (mSettingsStore.isAirplaneModeOn() && !isFromSettings) {
793            mLog.info("setWifiEnabled in Airplane mode: only Settings can enable wifi").flush();
794            return false;
795        }
796
797        // If SoftAp is enabled, only Settings is allowed to toggle wifi
798        boolean apEnabled =
799                mWifiStateMachine.syncGetWifiApState() != WifiManager.WIFI_AP_STATE_DISABLED;
800
801        if (apEnabled && !isFromSettings) {
802            mLog.info("setWifiEnabled SoftAp not disabled: only Settings can enable wifi").flush();
803            return false;
804        }
805
806        /*
807        * Caller might not have WRITE_SECURE_SETTINGS,
808        * only CHANGE_WIFI_STATE is enforced
809        */
810        long ident = Binder.clearCallingIdentity();
811        try {
812            if (! mSettingsStore.handleWifiToggled(enable)) {
813                // Nothing to do if wifi cannot be toggled
814                return true;
815            }
816        } finally {
817            Binder.restoreCallingIdentity(ident);
818        }
819
820
821        if (mPermissionReviewRequired) {
822            final int wiFiEnabledState = getWifiEnabledState();
823            if (enable) {
824                if (wiFiEnabledState == WifiManager.WIFI_STATE_DISABLING
825                        || wiFiEnabledState == WifiManager.WIFI_STATE_DISABLED) {
826                    if (startConsentUi(packageName, Binder.getCallingUid(),
827                            WifiManager.ACTION_REQUEST_ENABLE)) {
828                        return true;
829                    }
830                }
831            } else if (wiFiEnabledState == WifiManager.WIFI_STATE_ENABLING
832                    || wiFiEnabledState == WifiManager.WIFI_STATE_ENABLED) {
833                if (startConsentUi(packageName, Binder.getCallingUid(),
834                        WifiManager.ACTION_REQUEST_DISABLE)) {
835                    return true;
836                }
837            }
838        }
839
840        mWifiController.sendMessage(CMD_WIFI_TOGGLED);
841        return true;
842    }
843
844    /**
845     * see {@link WifiManager#getWifiState()}
846     * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
847     *         {@link WifiManager#WIFI_STATE_DISABLING},
848     *         {@link WifiManager#WIFI_STATE_ENABLED},
849     *         {@link WifiManager#WIFI_STATE_ENABLING},
850     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
851     */
852    @Override
853    public int getWifiEnabledState() {
854        enforceAccessPermission();
855        mLog.info("getWifiEnabledState uid=%").c(Binder.getCallingUid()).flush();
856        return mWifiStateMachine.syncGetWifiState();
857    }
858
859    /**
860     * see {@link android.net.wifi.WifiManager#setWifiApEnabled(WifiConfiguration, boolean)}
861     * @param wifiConfig SSID, security and channel details as
862     *        part of WifiConfiguration
863     * @param enabled true to enable and false to disable
864     */
865    @Override
866    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
867        enforceChangePermission();
868        mWifiPermissionsUtil.enforceTetherChangePermission(mContext);
869
870        mLog.info("setWifiApEnabled uid=% enable=%").c(Binder.getCallingUid()).c(enabled).flush();
871
872        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
873            throw new SecurityException("DISALLOW_CONFIG_TETHERING is enabled for this user.");
874        }
875        // null wifiConfig is a meaningful input for CMD_SET_AP
876        if (wifiConfig == null || isValid(wifiConfig)) {
877            int mode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
878            SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
879            mWifiController.sendMessage(CMD_SET_AP, enabled ? 1 : 0, 0, softApConfig);
880        } else {
881            Slog.e(TAG, "Invalid WifiConfiguration");
882        }
883    }
884
885    /**
886     * see {@link WifiManager#getWifiApState()}
887     * @return One of {@link WifiManager#WIFI_AP_STATE_DISABLED},
888     *         {@link WifiManager#WIFI_AP_STATE_DISABLING},
889     *         {@link WifiManager#WIFI_AP_STATE_ENABLED},
890     *         {@link WifiManager#WIFI_AP_STATE_ENABLING},
891     *         {@link WifiManager#WIFI_AP_STATE_FAILED}
892     */
893    @Override
894    public int getWifiApEnabledState() {
895        enforceAccessPermission();
896        mLog.info("getWifiApEnabledState uid=%").c(Binder.getCallingUid()).flush();
897        return mWifiStateMachine.syncGetWifiApState();
898    }
899
900    /**
901     * see {@link android.net.wifi.WifiManager#updateInterfaceIpState(String, int)}
902     *
903     * The possible modes include: {@link WifiManager#IFACE_IP_MODE_TETHERED},
904     *                             {@link WifiManager#IFACE_IP_MODE_LOCAL_ONLY},
905     *                             {@link WifiManager#IFACE_IP_MODE_CONFIGURATION_ERROR}
906     *
907     * @param ifaceName String name of the updated interface
908     * @param mode new operating mode of the interface
909     *
910     * @throws SecurityException if the caller does not have permission to call update
911     */
912    @Override
913    public void updateInterfaceIpState(String ifaceName, int mode) {
914        // NETWORK_STACK is a signature only permission.
915        enforceNetworkStackPermission();
916
917        // hand off the work to our handler thread
918        mClientHandler.post(() -> {
919            updateInterfaceIpStateInternal(ifaceName, mode);
920        });
921    }
922
923    private void updateInterfaceIpStateInternal(String ifaceName, int mode) {
924        // update interface IP state related to tethering and hotspot
925        synchronized (mLocalOnlyHotspotRequests) {
926            // update the mode tracker here - we clear out state below
927            Integer previousMode = WifiManager.IFACE_IP_MODE_UNSPECIFIED;
928            if (ifaceName != null) {
929                previousMode = mIfaceIpModes.put(ifaceName, mode);
930            }
931            Slog.d(TAG, "updateInterfaceIpState: ifaceName=" + ifaceName + " mode=" + mode
932                    + " previous mode= " + previousMode);
933
934            switch (mode) {
935                case WifiManager.IFACE_IP_MODE_LOCAL_ONLY:
936                    // first make sure we have registered requests..  otherwise clean up
937                    if (mLocalOnlyHotspotRequests.isEmpty()) {
938                        // we don't have requests...  stop the hotspot
939                        stopSoftAp();
940                        updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
941                        return;
942                    }
943                    // LOHS is ready to go!  Call our registered requestors!
944                    sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked();
945                    break;
946                case WifiManager.IFACE_IP_MODE_TETHERED:
947                    // we have tethered an interface. we don't really act on this now other than if
948                    // we have LOHS requests, and this is an issue.  return incompatible mode for
949                    // onFailed for the registered requestors since this can result from a race
950                    // between a tether request and a hotspot request (tethering wins).
951                    sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
952                            LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE);
953                    break;
954                case WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR:
955                    // there was an error setting up the hotspot...  trigger onFailed for the
956                    // registered LOHS requestors
957                    sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
958                            LocalOnlyHotspotCallback.ERROR_GENERIC);
959                    updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
960                    break;
961                case WifiManager.IFACE_IP_MODE_UNSPECIFIED:
962                    if (ifaceName == null) {
963                        // interface name is null, this is due to softap teardown.  clear all
964                        // entries for now.
965                        // TODO: Deal with individual interfaces when we receive updates for them
966                        mIfaceIpModes.clear();
967                        return;
968                    }
969                    break;
970                default:
971                    mLog.warn("updateInterfaceIpStateInternal: unknown mode %").c(mode).flush();
972            }
973        }
974    }
975
976    /**
977     * see {@link android.net.wifi.WifiManager#startSoftAp(WifiConfiguration)}
978     * @param wifiConfig SSID, security and channel details as part of WifiConfiguration
979     * @return {@code true} if softap start was triggered
980     * @throws SecurityException if the caller does not have permission to start softap
981     */
982    @Override
983    public boolean startSoftAp(WifiConfiguration wifiConfig) {
984        // NETWORK_STACK is a signature only permission.
985        enforceNetworkStackPermission();
986
987        mLog.info("startSoftAp uid=%").c(Binder.getCallingUid()).flush();
988
989        synchronized (mLocalOnlyHotspotRequests) {
990            // If a tethering request comes in while we have LOHS running (or requested), call stop
991            // for softap mode and restart softap with the tethering config.
992            if (!mLocalOnlyHotspotRequests.isEmpty()) {
993                stopSoftApInternal();
994            }
995
996            return startSoftApInternal(wifiConfig, WifiManager.IFACE_IP_MODE_TETHERED);
997        }
998    }
999
1000    /**
1001     * Internal method to start softap mode. Callers of this method should have already checked
1002     * proper permissions beyond the NetworkStack permission.
1003     */
1004    private boolean startSoftApInternal(WifiConfiguration wifiConfig, int mode) {
1005        mLog.trace("startSoftApInternal uid=% mode=%")
1006                .c(Binder.getCallingUid()).c(mode).flush();
1007
1008        // null wifiConfig is a meaningful input for CMD_SET_AP
1009        if (wifiConfig == null || isValid(wifiConfig)) {
1010            SoftApModeConfiguration softApConfig = new SoftApModeConfiguration(mode, wifiConfig);
1011            mWifiController.sendMessage(CMD_SET_AP, 1, 0, softApConfig);
1012            return true;
1013        }
1014        Slog.e(TAG, "Invalid WifiConfiguration");
1015        return false;
1016    }
1017
1018    /**
1019     * see {@link android.net.wifi.WifiManager#stopSoftAp()}
1020     * @return {@code true} if softap stop was triggered
1021     * @throws SecurityException if the caller does not have permission to stop softap
1022     */
1023    @Override
1024    public boolean stopSoftAp() {
1025        // NETWORK_STACK is a signature only permission.
1026        enforceNetworkStackPermission();
1027
1028        // only permitted callers are allowed to this point - they must have gone through
1029        // connectivity service since this method is protected with the NETWORK_STACK PERMISSION
1030
1031        mLog.info("stopSoftAp uid=%").c(Binder.getCallingUid()).flush();
1032
1033        synchronized (mLocalOnlyHotspotRequests) {
1034            // If a tethering request comes in while we have LOHS running (or requested), call stop
1035            // for softap mode and restart softap with the tethering config.
1036            if (!mLocalOnlyHotspotRequests.isEmpty()) {
1037                mLog.trace("Call to stop Tethering while LOHS is active,"
1038                        + " Registered LOHS callers will be updated when softap stopped.");
1039            }
1040
1041            return stopSoftApInternal();
1042        }
1043    }
1044
1045    /**
1046     * Internal method to stop softap mode.  Callers of this method should have already checked
1047     * proper permissions beyond the NetworkStack permission.
1048     */
1049    private boolean stopSoftApInternal() {
1050        mLog.trace("stopSoftApInternal uid=%").c(Binder.getCallingUid()).flush();
1051
1052        mWifiController.sendMessage(CMD_SET_AP, 0, 0);
1053        return true;
1054    }
1055
1056    /**
1057     * Private method to handle SoftAp state changes
1058     */
1059    private void handleWifiApStateChange(
1060            int currentState, int previousState, int errorCode, String ifaceName, int mode) {
1061        // The AP state update from WifiStateMachine for softap
1062        Slog.d(TAG, "handleWifiApStateChange: currentState=" + currentState
1063                + " previousState=" + previousState + " errorCode= " + errorCode
1064                + " ifaceName=" + ifaceName + " mode=" + mode);
1065
1066        // check if we have a failure - since it is possible (worst case scenario where
1067        // WifiController and WifiStateMachine are out of sync wrt modes) to get two FAILED
1068        // notifications in a row, we need to handle this first.
1069        if (currentState == WIFI_AP_STATE_FAILED) {
1070            // update registered LOHS callbacks if we see a failure
1071            synchronized (mLocalOnlyHotspotRequests) {
1072                int errorToReport = ERROR_GENERIC;
1073                if (errorCode == SAP_START_FAILURE_NO_CHANNEL) {
1074                    errorToReport = ERROR_NO_CHANNEL;
1075                }
1076                // holding the required lock: send message to requestors and clear the list
1077                sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(
1078                        errorToReport);
1079                // also need to clear interface ip state - send null for now since we don't know
1080                // what interface (and we have one anyway)
1081                updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1082            }
1083            return;
1084        }
1085
1086        if (currentState == WIFI_AP_STATE_DISABLING || currentState == WIFI_AP_STATE_DISABLED) {
1087            // softap is shutting down or is down...  let requestors know via the onStopped call
1088            synchronized (mLocalOnlyHotspotRequests) {
1089                // if we are currently in hotspot mode, then trigger onStopped for registered
1090                // requestors, otherwise something odd happened and we should clear state
1091                if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
1092                    // holding the required lock: send message to requestors and clear the list
1093                    sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked();
1094                } else {
1095                    // LOHS not active: report an error (still holding the required lock)
1096                    sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(ERROR_GENERIC);
1097                }
1098                // also clear interface ip state - send null for now since we don't know what
1099                // interface (and we only have one anyway)
1100                updateInterfaceIpState(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1101            }
1102            return;
1103        }
1104
1105        // remaining states are enabling or enabled...  those are not used for the callbacks
1106    }
1107
1108    /**
1109     * Helper method to send a HOTSPOT_FAILED message to all registered LocalOnlyHotspotRequest
1110     * callers and clear the registrations.
1111     *
1112     * Callers should already hold the mLocalOnlyHotspotRequests lock.
1113     */
1114    private void sendHotspotFailedMessageToAllLOHSRequestInfoEntriesLocked(int arg1) {
1115        for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1116            try {
1117                requestor.sendHotspotFailedMessage(arg1);
1118                requestor.unlinkDeathRecipient();
1119            } catch (RemoteException e) {
1120                // This will be cleaned up by binder death handling
1121            }
1122        }
1123
1124        // Since all callers were notified, now clear the registrations.
1125        mLocalOnlyHotspotRequests.clear();
1126    }
1127
1128    /**
1129     * Helper method to send a HOTSPOT_STOPPED message to all registered LocalOnlyHotspotRequest
1130     * callers and clear the registrations.
1131     *
1132     * Callers should already hold the mLocalOnlyHotspotRequests lock.
1133     */
1134    private void sendHotspotStoppedMessageToAllLOHSRequestInfoEntriesLocked() {
1135        for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1136            try {
1137                requestor.sendHotspotStoppedMessage();
1138                requestor.unlinkDeathRecipient();
1139            } catch (RemoteException e) {
1140                // This will be cleaned up by binder death handling
1141            }
1142        }
1143
1144        // Since all callers were notified, now clear the registrations.
1145        mLocalOnlyHotspotRequests.clear();
1146    }
1147
1148    /**
1149     * Helper method to send a HOTSPOT_STARTED message to all registered LocalOnlyHotspotRequest
1150     * callers.
1151     *
1152     * Callers should already hold the mLocalOnlyHotspotRequests lock.
1153     */
1154    private void sendHotspotStartedMessageToAllLOHSRequestInfoEntriesLocked() {
1155        for (LocalOnlyHotspotRequestInfo requestor : mLocalOnlyHotspotRequests.values()) {
1156            try {
1157                requestor.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
1158            } catch (RemoteException e) {
1159                // This will be cleaned up by binder death handling
1160            }
1161        }
1162    }
1163
1164    /**
1165     * Temporary method used for testing while startLocalOnlyHotspot is not fully implemented.  This
1166     * method allows unit tests to register callbacks directly for testing mechanisms triggered by
1167     * softap mode changes.
1168     */
1169    @VisibleForTesting
1170    void registerLOHSForTest(int pid, LocalOnlyHotspotRequestInfo request) {
1171        mLocalOnlyHotspotRequests.put(pid, request);
1172    }
1173
1174    /**
1175     * Method to start LocalOnlyHotspot.  In this method, permissions, settings and modes are
1176     * checked to verify that we can enter softapmode.  This method returns
1177     * {@link LocalOnlyHotspotCallback#REQUEST_REGISTERED} if we will attempt to start, otherwise,
1178     * possible startup erros may include tethering being disallowed failure reason {@link
1179     * LocalOnlyHotspotCallback#ERROR_TETHERING_DISALLOWED} or an incompatible mode failure reason
1180     * {@link LocalOnlyHotspotCallback#ERROR_INCOMPATIBLE_MODE}.
1181     *
1182     * see {@link WifiManager#startLocalOnlyHotspot(LocalOnlyHotspotCallback)}
1183     *
1184     * @param messenger Messenger to send messages to the corresponding WifiManager.
1185     * @param binder IBinder instance to allow cleanup if the app dies
1186     * @param packageName String name of the calling package
1187     *
1188     * @return int return code for attempt to start LocalOnlyHotspot.
1189     *
1190     * @throws SecurityException if the caller does not have permission to start a Local Only
1191     * Hotspot.
1192     * @throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
1193     * have an outstanding request.
1194     */
1195    @Override
1196    public int startLocalOnlyHotspot(Messenger messenger, IBinder binder, String packageName) {
1197        // first check if the caller has permission to start a local only hotspot
1198        // need to check for WIFI_STATE_CHANGE and location permission
1199        final int uid = Binder.getCallingUid();
1200        final int pid = Binder.getCallingPid();
1201
1202        enforceChangePermission();
1203        enforceLocationPermission(packageName, uid);
1204        // also need to verify that Locations services are enabled.
1205        if (mSettingsStore.getLocationModeSetting(mContext) == Settings.Secure.LOCATION_MODE_OFF) {
1206            throw new SecurityException("Location mode is not enabled.");
1207        }
1208
1209        // verify that tethering is not disabled
1210        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
1211            return LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
1212        }
1213
1214        // the app should be in the foreground
1215        try {
1216            if (!mFrameworkFacade.isAppForeground(uid)) {
1217                return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1218            }
1219        } catch (RemoteException e) {
1220            mLog.warn("RemoteException during isAppForeground when calling startLOHS");
1221            return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1222        }
1223
1224        mLog.info("startLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
1225
1226        synchronized (mLocalOnlyHotspotRequests) {
1227            // check if we are currently tethering
1228            if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_TETHERED)) {
1229                // Tethering is enabled, cannot start LocalOnlyHotspot
1230                mLog.info("Cannot start localOnlyHotspot when WiFi Tethering is active.");
1231                return LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
1232            }
1233
1234            // does this caller already have a request?
1235            LocalOnlyHotspotRequestInfo request = mLocalOnlyHotspotRequests.get(pid);
1236            if (request != null) {
1237                mLog.trace("caller already has an active request");
1238                throw new IllegalStateException(
1239                        "Caller already has an active LocalOnlyHotspot request");
1240            }
1241
1242            // now create the new LOHS request info object
1243            request = new LocalOnlyHotspotRequestInfo(binder, messenger,
1244                    new LocalOnlyRequestorCallback());
1245
1246            // check current operating state and take action if needed
1247            if (mIfaceIpModes.contains(WifiManager.IFACE_IP_MODE_LOCAL_ONLY)) {
1248                // LOHS is already active, send out what is running
1249                try {
1250                    mLog.trace("LOHS already up, trigger onStarted callback");
1251                    request.sendHotspotStartedMessage(mLocalOnlyHotspotConfig);
1252                } catch (RemoteException e) {
1253                    return LocalOnlyHotspotCallback.ERROR_GENERIC;
1254                }
1255            } else if (mLocalOnlyHotspotRequests.isEmpty()) {
1256                // this is the first request, then set up our config and start LOHS
1257                mLocalOnlyHotspotConfig =
1258                        WifiApConfigStore.generateLocalOnlyHotspotConfig(mContext);
1259                startSoftApInternal(mLocalOnlyHotspotConfig, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
1260            }
1261
1262            mLocalOnlyHotspotRequests.put(pid, request);
1263            return LocalOnlyHotspotCallback.REQUEST_REGISTERED;
1264        }
1265    }
1266
1267    /**
1268     * see {@link WifiManager#stopLocalOnlyHotspot()}
1269     *
1270     * @throws SecurityException if the caller does not have permission to stop a Local Only
1271     * Hotspot.
1272     */
1273    @Override
1274    public void stopLocalOnlyHotspot() {
1275        // first check if the caller has permission to stop a local only hotspot
1276        enforceChangePermission();
1277        final int uid = Binder.getCallingUid();
1278        final int pid = Binder.getCallingPid();
1279
1280        mLog.info("stopLocalOnlyHotspot uid=% pid=%").c(uid).c(pid).flush();
1281
1282        synchronized (mLocalOnlyHotspotRequests) {
1283            // was the caller already registered?  check request tracker - return false if not
1284            LocalOnlyHotspotRequestInfo requestInfo = mLocalOnlyHotspotRequests.get(pid);
1285            if (requestInfo == null) {
1286                return;
1287            }
1288            requestInfo.unlinkDeathRecipient();
1289            unregisterCallingAppAndStopLocalOnlyHotspot(requestInfo);
1290        } // end synchronized
1291    }
1292
1293    /**
1294     * Helper method to unregister LocalOnlyHotspot requestors and stop the hotspot if needed.
1295     */
1296    private void unregisterCallingAppAndStopLocalOnlyHotspot(LocalOnlyHotspotRequestInfo request) {
1297        mLog.trace("unregisterCallingAppAndStopLocalOnlyHotspot pid=%").c(request.getPid()).flush();
1298
1299        synchronized (mLocalOnlyHotspotRequests) {
1300            if (mLocalOnlyHotspotRequests.remove(request.getPid()) == null) {
1301                mLog.trace("LocalOnlyHotspotRequestInfo not found to remove");
1302                return;
1303            }
1304
1305            if (mLocalOnlyHotspotRequests.isEmpty()) {
1306                mLocalOnlyHotspotConfig = null;
1307                updateInterfaceIpStateInternal(null, WifiManager.IFACE_IP_MODE_UNSPECIFIED);
1308                // if that was the last caller, then call stopSoftAp as WifiService
1309                long identity = Binder.clearCallingIdentity();
1310                try {
1311                    stopSoftApInternal();
1312                } finally {
1313                    Binder.restoreCallingIdentity(identity);
1314                }
1315            }
1316        }
1317    }
1318
1319    /**
1320     * see {@link WifiManager#watchLocalOnlyHotspot(LocalOnlyHotspotObserver)}
1321     *
1322     * This call requires the android.permission.NETWORK_SETTINGS permission.
1323     *
1324     * @param messenger Messenger to send messages to the corresponding WifiManager.
1325     * @param binder IBinder instance to allow cleanup if the app dies
1326     *
1327     * @throws SecurityException if the caller does not have permission to watch Local Only Hotspot
1328     * status updates.
1329     * @throws IllegalStateException if the caller attempts to watch LocalOnlyHotspot updates with
1330     * an existing subscription.
1331     */
1332    @Override
1333    public void startWatchLocalOnlyHotspot(Messenger messenger, IBinder binder) {
1334        final String packageName = mContext.getOpPackageName();
1335
1336        // NETWORK_SETTINGS is a signature only permission.
1337        enforceNetworkSettingsPermission();
1338
1339        throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1340    }
1341
1342    /**
1343     * see {@link WifiManager#unregisterLocalOnlyHotspotObserver()}
1344     */
1345    @Override
1346    public void stopWatchLocalOnlyHotspot() {
1347        // NETWORK_STACK is a signature only permission.
1348        enforceNetworkSettingsPermission();
1349        throw new UnsupportedOperationException("LocalOnlyHotspot is still in development");
1350    }
1351
1352    /**
1353     * see {@link WifiManager#getWifiApConfiguration()}
1354     * @return soft access point configuration
1355     * @throws SecurityException if the caller does not have permission to retrieve the softap
1356     * config
1357     */
1358    @Override
1359    public WifiConfiguration getWifiApConfiguration() {
1360        enforceAccessPermission();
1361        int uid = Binder.getCallingUid();
1362        // only allow Settings UI to get the saved SoftApConfig
1363        if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1364            // random apps should not be allowed to read the user specified config
1365            throw new SecurityException("App not allowed to read or update stored WiFi Ap config "
1366                    + "(uid = " + uid + ")");
1367        }
1368        mLog.info("getWifiApConfiguration uid=%").c(uid).flush();
1369        return mWifiStateMachine.syncGetWifiApConfiguration();
1370    }
1371
1372    /**
1373     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
1374     * @param wifiConfig WifiConfiguration details for soft access point
1375     * @throws SecurityException if the caller does not have permission to write the sotap config
1376     */
1377    @Override
1378    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
1379        enforceChangePermission();
1380        int uid = Binder.getCallingUid();
1381        // only allow Settings UI to write the stored SoftApConfig
1382        if (!mWifiPermissionsUtil.checkConfigOverridePermission(uid)) {
1383            // random apps should not be allowed to read the user specified config
1384            throw new SecurityException("App not allowed to read or update stored WiFi AP config "
1385                    + "(uid = " + uid + ")");
1386        }
1387        mLog.info("setWifiApConfiguration uid=%").c(uid).flush();
1388        if (wifiConfig == null)
1389            return;
1390        if (isValid(wifiConfig)) {
1391            mWifiStateMachine.setWifiApConfiguration(wifiConfig);
1392        } else {
1393            Slog.e(TAG, "Invalid WifiConfiguration");
1394        }
1395    }
1396
1397    /**
1398     * see {@link android.net.wifi.WifiManager#isScanAlwaysAvailable()}
1399     */
1400    @Override
1401    public boolean isScanAlwaysAvailable() {
1402        enforceAccessPermission();
1403        mLog.info("isScanAlwaysAvailable uid=%").c(Binder.getCallingUid()).flush();
1404        return mSettingsStore.isScanAlwaysAvailable();
1405    }
1406
1407    /**
1408     * see {@link android.net.wifi.WifiManager#disconnect()}
1409     */
1410    @Override
1411    public void disconnect() {
1412        enforceChangePermission();
1413        mLog.info("disconnect uid=%").c(Binder.getCallingUid()).flush();
1414        mWifiStateMachine.disconnectCommand();
1415    }
1416
1417    /**
1418     * see {@link android.net.wifi.WifiManager#reconnect()}
1419     */
1420    @Override
1421    public void reconnect() {
1422        enforceChangePermission();
1423        mLog.info("reconnect uid=%").c(Binder.getCallingUid()).flush();
1424        mWifiStateMachine.reconnectCommand(new WorkSource(Binder.getCallingUid()));
1425    }
1426
1427    /**
1428     * see {@link android.net.wifi.WifiManager#reassociate()}
1429     */
1430    @Override
1431    public void reassociate() {
1432        enforceChangePermission();
1433        mLog.info("reassociate uid=%").c(Binder.getCallingUid()).flush();
1434        mWifiStateMachine.reassociateCommand();
1435    }
1436
1437    /**
1438     * see {@link android.net.wifi.WifiManager#getSupportedFeatures}
1439     */
1440    @Override
1441    public int getSupportedFeatures() {
1442        enforceAccessPermission();
1443        mLog.info("getSupportedFeatures uid=%").c(Binder.getCallingUid()).flush();
1444        if (mWifiStateMachineChannel != null) {
1445            return mWifiStateMachine.syncGetSupportedFeatures(mWifiStateMachineChannel);
1446        } else {
1447            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1448            return 0;
1449        }
1450    }
1451
1452    @Override
1453    public void requestActivityInfo(ResultReceiver result) {
1454        Bundle bundle = new Bundle();
1455        mLog.info("requestActivityInfo uid=%").c(Binder.getCallingUid()).flush();
1456        bundle.putParcelable(BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY, reportActivityInfo());
1457        result.send(0, bundle);
1458    }
1459
1460    /**
1461     * see {@link android.net.wifi.WifiManager#getControllerActivityEnergyInfo(int)}
1462     */
1463    @Override
1464    public WifiActivityEnergyInfo reportActivityInfo() {
1465        enforceAccessPermission();
1466        mLog.info("reportActivityInfo uid=%").c(Binder.getCallingUid()).flush();
1467        if ((getSupportedFeatures() & WifiManager.WIFI_FEATURE_LINK_LAYER_STATS) == 0) {
1468            return null;
1469        }
1470        WifiLinkLayerStats stats;
1471        WifiActivityEnergyInfo energyInfo = null;
1472        if (mWifiStateMachineChannel != null) {
1473            stats = mWifiStateMachine.syncGetLinkLayerStats(mWifiStateMachineChannel);
1474            if (stats != null) {
1475                final long rxIdleCurrent = mContext.getResources().getInteger(
1476                        com.android.internal.R.integer.config_wifi_idle_receive_cur_ma);
1477                final long rxCurrent = mContext.getResources().getInteger(
1478                        com.android.internal.R.integer.config_wifi_active_rx_cur_ma);
1479                final long txCurrent = mContext.getResources().getInteger(
1480                        com.android.internal.R.integer.config_wifi_tx_cur_ma);
1481                final double voltage = mContext.getResources().getInteger(
1482                        com.android.internal.R.integer.config_wifi_operating_voltage_mv)
1483                        / 1000.0;
1484
1485                final long rxIdleTime = stats.on_time - stats.tx_time - stats.rx_time;
1486                final long[] txTimePerLevel;
1487                if (stats.tx_time_per_level != null) {
1488                    txTimePerLevel = new long[stats.tx_time_per_level.length];
1489                    for (int i = 0; i < txTimePerLevel.length; i++) {
1490                        txTimePerLevel[i] = stats.tx_time_per_level[i];
1491                        // TODO(b/27227497): Need to read the power consumed per level from config
1492                    }
1493                } else {
1494                    // This will happen if the HAL get link layer API returned null.
1495                    txTimePerLevel = new long[0];
1496                }
1497                final long energyUsed = (long)((stats.tx_time * txCurrent +
1498                        stats.rx_time * rxCurrent +
1499                        rxIdleTime * rxIdleCurrent) * voltage);
1500                if (VDBG || rxIdleTime < 0 || stats.on_time < 0 || stats.tx_time < 0 ||
1501                        stats.rx_time < 0 || energyUsed < 0) {
1502                    StringBuilder sb = new StringBuilder();
1503                    sb.append(" rxIdleCur=" + rxIdleCurrent);
1504                    sb.append(" rxCur=" + rxCurrent);
1505                    sb.append(" txCur=" + txCurrent);
1506                    sb.append(" voltage=" + voltage);
1507                    sb.append(" on_time=" + stats.on_time);
1508                    sb.append(" tx_time=" + stats.tx_time);
1509                    sb.append(" tx_time_per_level=" + Arrays.toString(txTimePerLevel));
1510                    sb.append(" rx_time=" + stats.rx_time);
1511                    sb.append(" rxIdleTime=" + rxIdleTime);
1512                    sb.append(" energy=" + energyUsed);
1513                    Log.d(TAG, " reportActivityInfo: " + sb.toString());
1514                }
1515
1516                // Convert the LinkLayerStats into EnergyActivity
1517                energyInfo = new WifiActivityEnergyInfo(mClock.getElapsedSinceBootMillis(),
1518                        WifiActivityEnergyInfo.STACK_STATE_STATE_IDLE, stats.tx_time,
1519                        txTimePerLevel, stats.rx_time, rxIdleTime, energyUsed);
1520            }
1521            if (energyInfo != null && energyInfo.isValid()) {
1522                return energyInfo;
1523            } else {
1524                return null;
1525            }
1526        } else {
1527            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1528            return null;
1529        }
1530    }
1531
1532    /**
1533     * see {@link android.net.wifi.WifiManager#getConfiguredNetworks()}
1534     * @return the list of configured networks
1535     */
1536    @Override
1537    public ParceledListSlice<WifiConfiguration> getConfiguredNetworks() {
1538        enforceAccessPermission();
1539        mLog.info("getConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
1540        if (mWifiStateMachineChannel != null) {
1541            List<WifiConfiguration> configs = mWifiStateMachine.syncGetConfiguredNetworks(
1542                    Binder.getCallingUid(), mWifiStateMachineChannel);
1543            if (configs != null) {
1544                return new ParceledListSlice<WifiConfiguration>(configs);
1545            }
1546        } else {
1547            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1548        }
1549        return null;
1550    }
1551
1552    /**
1553     * see {@link android.net.wifi.WifiManager#getPrivilegedConfiguredNetworks()}
1554     * @return the list of configured networks with real preSharedKey
1555     */
1556    @Override
1557    public ParceledListSlice<WifiConfiguration> getPrivilegedConfiguredNetworks() {
1558        enforceReadCredentialPermission();
1559        enforceAccessPermission();
1560        mLog.info("getPrivilegedConfiguredNetworks uid=%").c(Binder.getCallingUid()).flush();
1561        if (mWifiStateMachineChannel != null) {
1562            List<WifiConfiguration> configs =
1563                    mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
1564            if (configs != null) {
1565                return new ParceledListSlice<WifiConfiguration>(configs);
1566            }
1567        } else {
1568            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1569        }
1570        return null;
1571    }
1572
1573    /**
1574     * Returns a WifiConfiguration for a Passpoint network matching this ScanResult.
1575     *
1576     * @param scanResult scanResult that represents the BSSID
1577     * @return {@link WifiConfiguration} that matches this BSSID or null
1578     */
1579    @Override
1580    public WifiConfiguration getMatchingWifiConfig(ScanResult scanResult) {
1581        enforceAccessPermission();
1582        mLog.info("getMatchingWifiConfig uid=%").c(Binder.getCallingUid()).flush();
1583        if (!mContext.getPackageManager().hasSystemFeature(
1584                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1585            throw new UnsupportedOperationException("Passpoint not enabled");
1586        }
1587        return mWifiStateMachine.syncGetMatchingWifiConfig(scanResult, mWifiStateMachineChannel);
1588    }
1589
1590    /**
1591     * Returns list of OSU (Online Sign-Up) providers associated with the given Passpoint network.
1592     *
1593     * @param scanResult scanResult of the Passpoint AP
1594     * @return List of {@link OsuProvider}
1595     */
1596    @Override
1597    public List<OsuProvider> getMatchingOsuProviders(ScanResult scanResult) {
1598        enforceAccessPermission();
1599        mLog.info("getMatchingOsuProviders uid=%").c(Binder.getCallingUid()).flush();
1600        if (!mContext.getPackageManager().hasSystemFeature(
1601                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1602            throw new UnsupportedOperationException("Passpoint not enabled");
1603        }
1604        return mWifiStateMachine.syncGetMatchingOsuProviders(scanResult, mWifiStateMachineChannel);
1605    }
1606
1607    /**
1608     * see {@link android.net.wifi.WifiManager#addOrUpdateNetwork(WifiConfiguration)}
1609     * @return the supplicant-assigned identifier for the new or updated
1610     * network if the operation succeeds, or {@code -1} if it fails
1611     */
1612    @Override
1613    public int addOrUpdateNetwork(WifiConfiguration config) {
1614        enforceChangePermission();
1615        mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
1616
1617        // Previously, this API is overloaded for installing Passpoint profiles.  Now
1618        // that we have a dedicated API for doing it, redirect the call to the dedicated API.
1619        if (config.isPasspoint()) {
1620            PasspointConfiguration passpointConfig =
1621                    PasspointProvider.convertFromWifiConfig(config);
1622            if (passpointConfig.getCredential() == null) {
1623                Slog.e(TAG, "Missing credential for Passpoint profile");
1624                return -1;
1625            }
1626            // Copy over certificates and keys.
1627            passpointConfig.getCredential().setCaCertificate(
1628                    config.enterpriseConfig.getCaCertificate());
1629            passpointConfig.getCredential().setClientCertificateChain(
1630                    config.enterpriseConfig.getClientCertificateChain());
1631            passpointConfig.getCredential().setClientPrivateKey(
1632                    config.enterpriseConfig.getClientPrivateKey());
1633            if (!addOrUpdatePasspointConfiguration(passpointConfig)) {
1634                Slog.e(TAG, "Failed to add Passpoint profile");
1635                return -1;
1636            }
1637            // There is no network ID associated with a Passpoint profile.
1638            return 0;
1639        }
1640
1641        if (config != null) {
1642            //TODO: pass the Uid the WifiStateMachine as a message parameter
1643            Slog.i("addOrUpdateNetwork", " uid = " + Integer.toString(Binder.getCallingUid())
1644                    + " SSID " + config.SSID
1645                    + " nid=" + Integer.toString(config.networkId));
1646            if (config.networkId == WifiConfiguration.INVALID_NETWORK_ID) {
1647                config.creatorUid = Binder.getCallingUid();
1648            } else {
1649                config.lastUpdateUid = Binder.getCallingUid();
1650            }
1651            if (mWifiStateMachineChannel != null) {
1652                return mWifiStateMachine.syncAddOrUpdateNetwork(mWifiStateMachineChannel, config);
1653            } else {
1654                Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1655                return -1;
1656            }
1657        } else {
1658            Slog.e(TAG, "bad network configuration");
1659            return -1;
1660        }
1661    }
1662
1663    public static void verifyCert(X509Certificate caCert)
1664            throws GeneralSecurityException, IOException {
1665        CertificateFactory factory = CertificateFactory.getInstance("X.509");
1666        CertPathValidator validator =
1667                CertPathValidator.getInstance(CertPathValidator.getDefaultType());
1668        CertPath path = factory.generateCertPath(
1669                Arrays.asList(caCert));
1670        KeyStore ks = KeyStore.getInstance("AndroidCAStore");
1671        ks.load(null, null);
1672        PKIXParameters params = new PKIXParameters(ks);
1673        params.setRevocationEnabled(false);
1674        validator.validate(path, params);
1675    }
1676
1677    /**
1678     * See {@link android.net.wifi.WifiManager#removeNetwork(int)}
1679     * @param netId the integer that identifies the network configuration
1680     * to the supplicant
1681     * @return {@code true} if the operation succeeded
1682     */
1683    @Override
1684    public boolean removeNetwork(int netId) {
1685        enforceChangePermission();
1686        mLog.info("removeNetwork uid=%").c(Binder.getCallingUid()).flush();
1687        // TODO Add private logging for netId b/33807876
1688        if (mWifiStateMachineChannel != null) {
1689            return mWifiStateMachine.syncRemoveNetwork(mWifiStateMachineChannel, netId);
1690        } else {
1691            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1692            return false;
1693        }
1694    }
1695
1696    /**
1697     * See {@link android.net.wifi.WifiManager#enableNetwork(int, boolean)}
1698     * @param netId the integer that identifies the network configuration
1699     * to the supplicant
1700     * @param disableOthers if true, disable all other networks.
1701     * @return {@code true} if the operation succeeded
1702     */
1703    @Override
1704    public boolean enableNetwork(int netId, boolean disableOthers) {
1705        enforceChangePermission();
1706        // TODO b/33807876 Log netId
1707        mLog.info("enableNetwork uid=% disableOthers=%")
1708                .c(Binder.getCallingUid())
1709                .c(disableOthers).flush();
1710
1711        if (mWifiStateMachineChannel != null) {
1712            return mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, netId,
1713                    disableOthers);
1714        } else {
1715            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1716            return false;
1717        }
1718    }
1719
1720    /**
1721     * See {@link android.net.wifi.WifiManager#disableNetwork(int)}
1722     * @param netId the integer that identifies the network configuration
1723     * to the supplicant
1724     * @return {@code true} if the operation succeeded
1725     */
1726    @Override
1727    public boolean disableNetwork(int netId) {
1728        enforceChangePermission();
1729        // TODO b/33807876 Log netId
1730        mLog.info("disableNetwork uid=%").c(Binder.getCallingUid()).flush();
1731
1732        if (mWifiStateMachineChannel != null) {
1733            return mWifiStateMachine.syncDisableNetwork(mWifiStateMachineChannel, netId);
1734        } else {
1735            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1736            return false;
1737        }
1738    }
1739
1740    /**
1741     * See {@link android.net.wifi.WifiManager#getConnectionInfo()}
1742     * @return the Wi-Fi information, contained in {@link WifiInfo}.
1743     */
1744    @Override
1745    public WifiInfo getConnectionInfo(String callingPackage) {
1746        enforceAccessPermission();
1747        mLog.info("getConnectionInfo uid=%").c(Binder.getCallingUid()).flush();
1748        /*
1749         * Make sure we have the latest information, by sending
1750         * a status request to the supplicant.
1751         */
1752        return mWifiStateMachine.syncRequestConnectionInfo(callingPackage);
1753    }
1754
1755    /**
1756     * Return the results of the most recent access point scan, in the form of
1757     * a list of {@link ScanResult} objects.
1758     * @return the list of results
1759     */
1760    @Override
1761    public List<ScanResult> getScanResults(String callingPackage) {
1762        enforceAccessPermission();
1763        int uid = Binder.getCallingUid();
1764        long ident = Binder.clearCallingIdentity();
1765        try {
1766            if (!mWifiPermissionsUtil.canAccessScanResults(callingPackage,
1767                      uid, Build.VERSION_CODES.M)) {
1768                return new ArrayList<ScanResult>();
1769            }
1770            if (mWifiScanner == null) {
1771                mWifiScanner = mWifiInjector.getWifiScanner();
1772            }
1773            return mWifiScanner.getSingleScanResults();
1774        } finally {
1775            Binder.restoreCallingIdentity(ident);
1776        }
1777    }
1778
1779    /**
1780     * Add or update a Passpoint configuration.
1781     *
1782     * @param config The Passpoint configuration to be added
1783     * @return true on success or false on failure
1784     */
1785    @Override
1786    public boolean addOrUpdatePasspointConfiguration(PasspointConfiguration config) {
1787        enforceChangePermission();
1788        mLog.info("addorUpdatePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1789        if (!mContext.getPackageManager().hasSystemFeature(
1790                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1791            throw new UnsupportedOperationException("Passpoint not enabled");
1792        }
1793        return mWifiStateMachine.syncAddOrUpdatePasspointConfig(mWifiStateMachineChannel, config,
1794                Binder.getCallingUid());
1795    }
1796
1797    /**
1798     * Remove the Passpoint configuration identified by its FQDN (Fully Qualified Domain Name).
1799     *
1800     * @param fqdn The FQDN of the Passpoint configuration to be removed
1801     * @return true on success or false on failure
1802     */
1803    @Override
1804    public boolean removePasspointConfiguration(String fqdn) {
1805        enforceChangePermission();
1806        mLog.info("removePasspointConfiguration uid=%").c(Binder.getCallingUid()).flush();
1807        if (!mContext.getPackageManager().hasSystemFeature(
1808                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1809            throw new UnsupportedOperationException("Passpoint not enabled");
1810        }
1811        return mWifiStateMachine.syncRemovePasspointConfig(mWifiStateMachineChannel, fqdn);
1812    }
1813
1814    /**
1815     * Return the list of the installed Passpoint configurations.
1816     *
1817     * An empty list will be returned when no configuration is installed.
1818     *
1819     * @return A list of {@link PasspointConfiguration}
1820     */
1821    @Override
1822    public List<PasspointConfiguration> getPasspointConfigurations() {
1823        enforceAccessPermission();
1824        mLog.info("getPasspointConfigurations uid=%").c(Binder.getCallingUid()).flush();
1825        if (!mContext.getPackageManager().hasSystemFeature(
1826                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1827            throw new UnsupportedOperationException("Passpoint not enabled");
1828        }
1829        return mWifiStateMachine.syncGetPasspointConfigs(mWifiStateMachineChannel);
1830    }
1831
1832    /**
1833     * Query for a Hotspot 2.0 release 2 OSU icon
1834     * @param bssid The BSSID of the AP
1835     * @param fileName Icon file name
1836     */
1837    @Override
1838    public void queryPasspointIcon(long bssid, String fileName) {
1839        enforceAccessPermission();
1840        mLog.info("queryPasspointIcon uid=%").c(Binder.getCallingUid()).flush();
1841        if (!mContext.getPackageManager().hasSystemFeature(
1842                PackageManager.FEATURE_WIFI_PASSPOINT)) {
1843            throw new UnsupportedOperationException("Passpoint not enabled");
1844        }
1845        mWifiStateMachine.syncQueryPasspointIcon(mWifiStateMachineChannel, bssid, fileName);
1846    }
1847
1848    /**
1849     * Match the currently associated network against the SP matching the given FQDN
1850     * @param fqdn FQDN of the SP
1851     * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
1852     */
1853    @Override
1854    public int matchProviderWithCurrentNetwork(String fqdn) {
1855        mLog.info("matchProviderWithCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
1856        return mWifiStateMachine.matchProviderWithCurrentNetwork(mWifiStateMachineChannel, fqdn);
1857    }
1858
1859    /**
1860     * Deauthenticate and set the re-authentication hold off time for the current network
1861     * @param holdoff hold off time in milliseconds
1862     * @param ess set if the hold off pertains to an ESS rather than a BSS
1863     */
1864    @Override
1865    public void deauthenticateNetwork(long holdoff, boolean ess) {
1866        mLog.info("deauthenticateNetwork uid=%").c(Binder.getCallingUid()).flush();
1867        mWifiStateMachine.deauthenticateNetwork(mWifiStateMachineChannel, holdoff, ess);
1868    }
1869
1870    /**
1871     * Tell the supplicant to persist the current list of configured networks.
1872     * @return {@code true} if the operation succeeded
1873     *
1874     * TODO: deprecate this
1875     */
1876    @Override
1877    public boolean saveConfiguration() {
1878        enforceChangePermission();
1879        mLog.info("saveConfiguration uid=%").c(Binder.getCallingUid()).flush();
1880        if (mWifiStateMachineChannel != null) {
1881            return mWifiStateMachine.syncSaveConfig(mWifiStateMachineChannel);
1882        } else {
1883            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
1884            return false;
1885        }
1886    }
1887
1888    /**
1889     * Set the country code
1890     * @param countryCode ISO 3166 country code.
1891     * @param persist {@code true} if the setting should be remembered.
1892     *
1893     * The persist behavior exists so that wifi can fall back to the last
1894     * persisted country code on a restart, when the locale information is
1895     * not available from telephony.
1896     */
1897    @Override
1898    public void setCountryCode(String countryCode, boolean persist) {
1899        Slog.i(TAG, "WifiService trying to set country code to " + countryCode +
1900                " with persist set to " + persist);
1901        enforceConnectivityInternalPermission();
1902        mLog.info("setCountryCode uid=%").c(Binder.getCallingUid()).flush();
1903        final long token = Binder.clearCallingIdentity();
1904        mCountryCode.setCountryCode(countryCode);
1905        Binder.restoreCallingIdentity(token);
1906    }
1907
1908     /**
1909     * Get the country code
1910     * @return Get the best choice country code for wifi, regardless of if it was set or
1911     * not.
1912     * Returns null when there is no country code available.
1913     */
1914    @Override
1915    public String getCountryCode() {
1916        enforceConnectivityInternalPermission();
1917        mLog.info("getCountryCode uid=%").c(Binder.getCallingUid()).flush();
1918        String country = mCountryCode.getCountryCode();
1919        return country;
1920    }
1921
1922    @Override
1923    public boolean isDualBandSupported() {
1924        //TODO: Should move towards adding a driver API that checks at runtime
1925        mLog.info("isDualBandSupported uid=%").c(Binder.getCallingUid()).flush();
1926        return mContext.getResources().getBoolean(
1927                com.android.internal.R.bool.config_wifi_dual_band_support);
1928    }
1929
1930    /**
1931     * Return the DHCP-assigned addresses from the last successful DHCP request,
1932     * if any.
1933     * @return the DHCP information
1934     * @deprecated
1935     */
1936    @Override
1937    @Deprecated
1938    public DhcpInfo getDhcpInfo() {
1939        enforceAccessPermission();
1940        mLog.info("getDhcpInfo uid=%").c(Binder.getCallingUid()).flush();
1941        DhcpResults dhcpResults = mWifiStateMachine.syncGetDhcpResults();
1942
1943        DhcpInfo info = new DhcpInfo();
1944
1945        if (dhcpResults.ipAddress != null &&
1946                dhcpResults.ipAddress.getAddress() instanceof Inet4Address) {
1947            info.ipAddress = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.ipAddress.getAddress());
1948        }
1949
1950        if (dhcpResults.gateway != null) {
1951            info.gateway = NetworkUtils.inetAddressToInt((Inet4Address) dhcpResults.gateway);
1952        }
1953
1954        int dnsFound = 0;
1955        for (InetAddress dns : dhcpResults.dnsServers) {
1956            if (dns instanceof Inet4Address) {
1957                if (dnsFound == 0) {
1958                    info.dns1 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1959                } else {
1960                    info.dns2 = NetworkUtils.inetAddressToInt((Inet4Address)dns);
1961                }
1962                if (++dnsFound > 1) break;
1963            }
1964        }
1965        Inet4Address serverAddress = dhcpResults.serverAddress;
1966        if (serverAddress != null) {
1967            info.serverAddress = NetworkUtils.inetAddressToInt(serverAddress);
1968        }
1969        info.leaseDuration = dhcpResults.leaseDuration;
1970
1971        return info;
1972    }
1973
1974    /**
1975     * enable TDLS for the local NIC to remote NIC
1976     * The APPs don't know the remote MAC address to identify NIC though,
1977     * so we need to do additional work to find it from remote IP address
1978     */
1979
1980    class TdlsTaskParams {
1981        public String remoteIpAddress;
1982        public boolean enable;
1983    }
1984
1985    class TdlsTask extends AsyncTask<TdlsTaskParams, Integer, Integer> {
1986        @Override
1987        protected Integer doInBackground(TdlsTaskParams... params) {
1988
1989            // Retrieve parameters for the call
1990            TdlsTaskParams param = params[0];
1991            String remoteIpAddress = param.remoteIpAddress.trim();
1992            boolean enable = param.enable;
1993
1994            // Get MAC address of Remote IP
1995            String macAddress = null;
1996
1997            BufferedReader reader = null;
1998
1999            try {
2000                reader = new BufferedReader(new FileReader("/proc/net/arp"));
2001
2002                // Skip over the line bearing colum titles
2003                String line = reader.readLine();
2004
2005                while ((line = reader.readLine()) != null) {
2006                    String[] tokens = line.split("[ ]+");
2007                    if (tokens.length < 6) {
2008                        continue;
2009                    }
2010
2011                    // ARP column format is
2012                    // Address HWType HWAddress Flags Mask IFace
2013                    String ip = tokens[0];
2014                    String mac = tokens[3];
2015
2016                    if (remoteIpAddress.equals(ip)) {
2017                        macAddress = mac;
2018                        break;
2019                    }
2020                }
2021
2022                if (macAddress == null) {
2023                    Slog.w(TAG, "Did not find remoteAddress {" + remoteIpAddress + "} in " +
2024                            "/proc/net/arp");
2025                } else {
2026                    enableTdlsWithMacAddress(macAddress, enable);
2027                }
2028
2029            } catch (FileNotFoundException e) {
2030                Slog.e(TAG, "Could not open /proc/net/arp to lookup mac address");
2031            } catch (IOException e) {
2032                Slog.e(TAG, "Could not read /proc/net/arp to lookup mac address");
2033            } finally {
2034                try {
2035                    if (reader != null) {
2036                        reader.close();
2037                    }
2038                }
2039                catch (IOException e) {
2040                    // Do nothing
2041                }
2042            }
2043
2044            return 0;
2045        }
2046    }
2047
2048    @Override
2049    public void enableTdls(String remoteAddress, boolean enable) {
2050        if (remoteAddress == null) {
2051          throw new IllegalArgumentException("remoteAddress cannot be null");
2052        }
2053        mLog.info("enableTdls uid=% enable=%").c(Binder.getCallingUid()).c(enable).flush();
2054        TdlsTaskParams params = new TdlsTaskParams();
2055        params.remoteIpAddress = remoteAddress;
2056        params.enable = enable;
2057        new TdlsTask().execute(params);
2058    }
2059
2060
2061    @Override
2062    public void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable) {
2063        mLog.info("enableTdlsWithMacAddress uid=% enable=%")
2064                .c(Binder.getCallingUid())
2065                .c(enable)
2066                .flush();
2067        if (remoteMacAddress == null) {
2068          throw new IllegalArgumentException("remoteMacAddress cannot be null");
2069        }
2070
2071        mWifiStateMachine.enableTdls(remoteMacAddress, enable);
2072    }
2073
2074    /**
2075     * Get a reference to handler. This is used by a client to establish
2076     * an AsyncChannel communication with WifiService
2077     */
2078    @Override
2079    public Messenger getWifiServiceMessenger() {
2080        enforceAccessPermission();
2081        enforceChangePermission();
2082        mLog.info("getWifiServiceMessenger uid=%").c(Binder.getCallingUid()).flush();
2083        return new Messenger(mClientHandler);
2084    }
2085
2086    /**
2087     * Disable an ephemeral network, i.e. network that is created thru a WiFi Scorer
2088     */
2089    @Override
2090    public void disableEphemeralNetwork(String SSID) {
2091        enforceAccessPermission();
2092        enforceChangePermission();
2093        mLog.info("disableEphemeralNetwork uid=%").c(Binder.getCallingUid()).flush();
2094        mWifiStateMachine.disableEphemeralNetwork(SSID);
2095    }
2096
2097    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2098        @Override
2099        public void onReceive(Context context, Intent intent) {
2100            String action = intent.getAction();
2101            if (action.equals(Intent.ACTION_SCREEN_ON)) {
2102                mWifiController.sendMessage(CMD_SCREEN_ON);
2103            } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
2104                mWifiController.sendMessage(CMD_USER_PRESENT);
2105            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
2106                mWifiController.sendMessage(CMD_SCREEN_OFF);
2107            } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
2108                int pluggedType = intent.getIntExtra("plugged", 0);
2109                mWifiController.sendMessage(CMD_BATTERY_CHANGED, pluggedType, 0, null);
2110            } else if (action.equals(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED)) {
2111                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
2112                        BluetoothAdapter.STATE_DISCONNECTED);
2113                mWifiStateMachine.sendBluetoothAdapterStateChange(state);
2114            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED)) {
2115                boolean emergencyMode = intent.getBooleanExtra("phoneinECMState", false);
2116                mWifiController.sendMessage(CMD_EMERGENCY_MODE_CHANGED, emergencyMode ? 1 : 0, 0);
2117            } else if (action.equals(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED)) {
2118                boolean inCall = intent.getBooleanExtra(PhoneConstants.PHONE_IN_EMERGENCY_CALL, false);
2119                mWifiController.sendMessage(CMD_EMERGENCY_CALL_STATE_CHANGED, inCall ? 1 : 0, 0);
2120            } else if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
2121                handleIdleModeChanged();
2122            }
2123        }
2124    };
2125
2126    private boolean startConsentUi(String packageName,
2127            int callingUid, String intentAction) throws RemoteException {
2128        if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
2129            return false;
2130        }
2131        try {
2132            // Validate the package only if we are going to use it
2133            ApplicationInfo applicationInfo = mContext.getPackageManager()
2134                    .getApplicationInfoAsUser(packageName,
2135                            PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
2136                            UserHandle.getUserId(callingUid));
2137            if (applicationInfo.uid != callingUid) {
2138                throw new SecurityException("Package " + callingUid
2139                        + " not in uid " + callingUid);
2140            }
2141
2142            // Permission review mode, trigger a user prompt
2143            Intent intent = new Intent(intentAction);
2144            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
2145                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
2146            intent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
2147            mContext.startActivity(intent);
2148            return true;
2149        } catch (PackageManager.NameNotFoundException e) {
2150            throw new RemoteException(e.getMessage());
2151        }
2152    }
2153
2154    /**
2155     * Observes settings changes to scan always mode.
2156     */
2157    private void registerForScanModeChange() {
2158        ContentObserver contentObserver = new ContentObserver(null) {
2159            @Override
2160            public void onChange(boolean selfChange) {
2161                mSettingsStore.handleWifiScanAlwaysAvailableToggled();
2162                mWifiController.sendMessage(CMD_SCAN_ALWAYS_MODE_CHANGED);
2163            }
2164        };
2165        mFrameworkFacade.registerContentObserver(mContext,
2166                Settings.Global.getUriFor(Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE),
2167                false, contentObserver);
2168
2169    }
2170
2171    // Monitors settings changes related to background wifi scan throttling.
2172    private void registerForBackgroundThrottleChanges() {
2173        mFrameworkFacade.registerContentObserver(
2174                mContext,
2175                Settings.Global.getUriFor(
2176                        Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS),
2177                false,
2178                new ContentObserver(null) {
2179                    @Override
2180                    public void onChange(boolean selfChange) {
2181                        updateBackgroundThrottleInterval();
2182                    }
2183                }
2184        );
2185        mFrameworkFacade.registerContentObserver(
2186                mContext,
2187                Settings.Global.getUriFor(
2188                        Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST),
2189                false,
2190                new ContentObserver(null) {
2191                    @Override
2192                    public void onChange(boolean selfChange) {
2193                        updateBackgroundThrottlingWhitelist();
2194                    }
2195                }
2196        );
2197    }
2198
2199    private void updateBackgroundThrottleInterval() {
2200        mBackgroundThrottleInterval = mFrameworkFacade.getLongSetting(
2201                mContext,
2202                Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
2203                DEFAULT_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS);
2204    }
2205
2206    private void updateBackgroundThrottlingWhitelist() {
2207        String setting = mFrameworkFacade.getStringSetting(
2208                mContext,
2209                Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST);
2210        mBackgroundThrottlePackageWhitelist.clear();
2211        if (setting != null) {
2212            mBackgroundThrottlePackageWhitelist.addAll(Arrays.asList(setting.split(",")));
2213        }
2214    }
2215
2216    private void registerForBroadcasts() {
2217        IntentFilter intentFilter = new IntentFilter();
2218        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2219        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
2220        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2221        intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
2222        intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
2223        intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
2224        intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALLBACK_MODE_CHANGED);
2225        intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2226
2227        boolean trackEmergencyCallState = mContext.getResources().getBoolean(
2228                com.android.internal.R.bool.config_wifi_turn_off_during_emergency_call);
2229        if (trackEmergencyCallState) {
2230            intentFilter.addAction(TelephonyIntents.ACTION_EMERGENCY_CALL_STATE_CHANGED);
2231        }
2232
2233        mContext.registerReceiver(mReceiver, intentFilter);
2234    }
2235
2236    private void registerForPackageOrUserRemoval() {
2237        IntentFilter intentFilter = new IntentFilter();
2238        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
2239        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
2240        mContext.registerReceiverAsUser(new BroadcastReceiver() {
2241            @Override
2242            public void onReceive(Context context, Intent intent) {
2243                switch (intent.getAction()) {
2244                    case Intent.ACTION_PACKAGE_REMOVED: {
2245                        if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
2246                            return;
2247                        }
2248                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
2249                        Uri uri = intent.getData();
2250                        if (uid == -1 || uri == null) {
2251                            return;
2252                        }
2253                        String pkgName = uri.getSchemeSpecificPart();
2254                        mWifiStateMachine.removeAppConfigs(pkgName, uid);
2255                        break;
2256                    }
2257                    case Intent.ACTION_USER_REMOVED: {
2258                        int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
2259                        mWifiStateMachine.removeUserConfigs(userHandle);
2260                        break;
2261                    }
2262                }
2263            }
2264        }, UserHandle.ALL, intentFilter, null, null);
2265    }
2266
2267    @Override
2268    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
2269            String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
2270        (new WifiShellCommand(mWifiStateMachine)).exec(this, in, out, err, args, callback,
2271                resultReceiver);
2272    }
2273
2274    @Override
2275    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2276        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2277                != PackageManager.PERMISSION_GRANTED) {
2278            pw.println("Permission Denial: can't dump WifiService from from pid="
2279                    + Binder.getCallingPid()
2280                    + ", uid=" + Binder.getCallingUid());
2281            return;
2282        }
2283        if (args != null && args.length > 0 && WifiMetrics.PROTO_DUMP_ARG.equals(args[0])) {
2284            // WifiMetrics proto bytes were requested. Dump only these.
2285            mWifiStateMachine.updateWifiMetrics();
2286            mWifiMetrics.dump(fd, pw, args);
2287        } else if (args != null && args.length > 0 && IpManager.DUMP_ARG.equals(args[0])) {
2288            // IpManager dump was requested. Pass it along and take no further action.
2289            String[] ipManagerArgs = new String[args.length - 1];
2290            System.arraycopy(args, 1, ipManagerArgs, 0, ipManagerArgs.length);
2291            mWifiStateMachine.dumpIpManager(fd, pw, ipManagerArgs);
2292        } else if (args != null && args.length > 0 && WifiScoreReport.DUMP_ARG.equals(args[0])) {
2293            WifiScoreReport wifiScoreReport = mWifiStateMachine.getWifiScoreReport();
2294            if (wifiScoreReport != null) wifiScoreReport.dump(fd, pw, args);
2295        } else {
2296            pw.println("Wi-Fi is " + mWifiStateMachine.syncGetWifiStateByName());
2297            pw.println("Stay-awake conditions: " +
2298                    mFacade.getIntegerSetting(mContext,
2299                            Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0));
2300            pw.println("mInIdleMode " + mInIdleMode);
2301            pw.println("mScanPending " + mScanPending);
2302            mWifiController.dump(fd, pw, args);
2303            mSettingsStore.dump(fd, pw, args);
2304            mTrafficPoller.dump(fd, pw, args);
2305            pw.println();
2306            pw.println("Locks held:");
2307            mWifiLockManager.dump(pw);
2308            pw.println();
2309            mWifiMulticastLockManager.dump(pw);
2310            pw.println();
2311            mWifiStateMachine.dump(fd, pw, args);
2312            pw.println();
2313            mWifiStateMachine.updateWifiMetrics();
2314            mWifiMetrics.dump(fd, pw, args);
2315            pw.println();
2316            mWifiBackupRestore.dump(fd, pw, args);
2317            pw.println();
2318            WifiScoreReport wifiScoreReport = mWifiStateMachine.getWifiScoreReport();
2319            if (wifiScoreReport != null) {
2320                pw.println("WifiScoreReport:");
2321                wifiScoreReport.dump(fd, pw, args);
2322            }
2323            pw.println();
2324        }
2325    }
2326
2327    @Override
2328    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag, WorkSource ws) {
2329        mLog.info("acquireWifiLock uid=% lockMode=%")
2330                .c(Binder.getCallingUid())
2331                .c(lockMode).flush();
2332        if (mWifiLockManager.acquireWifiLock(lockMode, tag, binder, ws)) {
2333            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
2334            return true;
2335        }
2336        return false;
2337    }
2338
2339    @Override
2340    public void updateWifiLockWorkSource(IBinder binder, WorkSource ws) {
2341        mLog.info("updateWifiLockWorkSource uid=%").c(Binder.getCallingUid()).flush();
2342        mWifiLockManager.updateWifiLockWorkSource(binder, ws);
2343    }
2344
2345    @Override
2346    public boolean releaseWifiLock(IBinder binder) {
2347        mLog.info("releaseWifiLock uid=%").c(Binder.getCallingUid()).flush();
2348        if (mWifiLockManager.releaseWifiLock(binder)) {
2349            mWifiController.sendMessage(CMD_LOCKS_CHANGED);
2350            return true;
2351        }
2352        return false;
2353    }
2354
2355    @Override
2356    public void initializeMulticastFiltering() {
2357        enforceMulticastChangePermission();
2358        mLog.info("initializeMulticastFiltering uid=%").c(Binder.getCallingUid()).flush();
2359        mWifiMulticastLockManager.initializeFiltering();
2360    }
2361
2362    @Override
2363    public void acquireMulticastLock(IBinder binder, String tag) {
2364        enforceMulticastChangePermission();
2365        mLog.info("acquireMulticastLock uid=%").c(Binder.getCallingUid()).flush();
2366        mWifiMulticastLockManager.acquireLock(binder, tag);
2367    }
2368
2369    @Override
2370    public void releaseMulticastLock() {
2371        enforceMulticastChangePermission();
2372        mLog.info("releaseMulticastLock uid=%").c(Binder.getCallingUid()).flush();
2373        mWifiMulticastLockManager.releaseLock();
2374    }
2375
2376    @Override
2377    public boolean isMulticastEnabled() {
2378        enforceAccessPermission();
2379        mLog.info("isMulticastEnabled uid=%").c(Binder.getCallingUid()).flush();
2380        return mWifiMulticastLockManager.isMulticastEnabled();
2381    }
2382
2383    @Override
2384    public void enableVerboseLogging(int verbose) {
2385        enforceAccessPermission();
2386        mLog.info("enableVerboseLogging uid=% verbose=%")
2387                .c(Binder.getCallingUid())
2388                .c(verbose).flush();
2389        mFacade.setIntegerSetting(
2390                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, verbose);
2391        enableVerboseLoggingInternal(verbose);
2392    }
2393
2394    void enableVerboseLoggingInternal(int verbose) {
2395        mWifiStateMachine.enableVerboseLogging(verbose);
2396        mWifiLockManager.enableVerboseLogging(verbose);
2397        mWifiMulticastLockManager.enableVerboseLogging(verbose);
2398        mWifiInjector.getWifiLastResortWatchdog().enableVerboseLogging(verbose);
2399        mWifiInjector.getWifiBackupRestore().enableVerboseLogging(verbose);
2400        LogcatLog.enableVerboseLogging(verbose);
2401    }
2402
2403    @Override
2404    public int getVerboseLoggingLevel() {
2405        enforceAccessPermission();
2406        mLog.info("getVerboseLoggingLevel uid=%").c(Binder.getCallingUid()).flush();
2407        return mFacade.getIntegerSetting(
2408                mContext, Settings.Global.WIFI_VERBOSE_LOGGING_ENABLED, 0);
2409    }
2410
2411    @Override
2412    public void enableAggressiveHandover(int enabled) {
2413        enforceAccessPermission();
2414        mLog.info("enableAggressiveHandover uid=% enabled=%")
2415            .c(Binder.getCallingUid())
2416            .c(enabled)
2417            .flush();
2418        mWifiStateMachine.enableAggressiveHandover(enabled);
2419    }
2420
2421    @Override
2422    public int getAggressiveHandover() {
2423        enforceAccessPermission();
2424        mLog.info("getAggressiveHandover uid=%").c(Binder.getCallingUid()).flush();
2425        return mWifiStateMachine.getAggressiveHandover();
2426    }
2427
2428    @Override
2429    public void setAllowScansWithTraffic(int enabled) {
2430        enforceAccessPermission();
2431        mLog.info("setAllowScansWithTraffic uid=% enabled=%")
2432                .c(Binder.getCallingUid())
2433                .c(enabled).flush();
2434        mWifiStateMachine.setAllowScansWithTraffic(enabled);
2435    }
2436
2437    @Override
2438    public int getAllowScansWithTraffic() {
2439        enforceAccessPermission();
2440        mLog.info("getAllowScansWithTraffic uid=%").c(Binder.getCallingUid()).flush();
2441        return mWifiStateMachine.getAllowScansWithTraffic();
2442    }
2443
2444    @Override
2445    public boolean setEnableAutoJoinWhenAssociated(boolean enabled) {
2446        enforceChangePermission();
2447        mLog.info("setEnableAutoJoinWhenAssociated uid=% enabled=%")
2448                .c(Binder.getCallingUid())
2449                .c(enabled).flush();
2450        return mWifiStateMachine.setEnableAutoJoinWhenAssociated(enabled);
2451    }
2452
2453    @Override
2454    public boolean getEnableAutoJoinWhenAssociated() {
2455        enforceAccessPermission();
2456        mLog.info("getEnableAutoJoinWhenAssociated uid=%").c(Binder.getCallingUid()).flush();
2457        return mWifiStateMachine.getEnableAutoJoinWhenAssociated();
2458    }
2459
2460    /* Return the Wifi Connection statistics object */
2461    @Override
2462    public WifiConnectionStatistics getConnectionStatistics() {
2463        enforceAccessPermission();
2464        enforceReadCredentialPermission();
2465        mLog.info("getConnectionStatistics uid=%").c(Binder.getCallingUid()).flush();
2466        if (mWifiStateMachineChannel != null) {
2467            return mWifiStateMachine.syncGetConnectionStatistics(mWifiStateMachineChannel);
2468        } else {
2469            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2470            return null;
2471        }
2472    }
2473
2474    @Override
2475    public void factoryReset() {
2476        enforceConnectivityInternalPermission();
2477        mLog.info("factoryReset uid=%").c(Binder.getCallingUid()).flush();
2478        if (mUserManager.hasUserRestriction(UserManager.DISALLOW_NETWORK_RESET)) {
2479            return;
2480        }
2481
2482        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
2483            // Turn mobile hotspot off - will also clear any registered LOHS requests when it is
2484            // shut down
2485            stopSoftApInternal();
2486        }
2487
2488        if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI)) {
2489            // Enable wifi
2490            try {
2491                setWifiEnabled(mContext.getOpPackageName(), true);
2492            } catch (RemoteException e) {
2493                /* ignore - local call */
2494            }
2495            // Delete all Wifi SSIDs
2496            if (mWifiStateMachineChannel != null) {
2497                List<WifiConfiguration> networks = mWifiStateMachine.syncGetConfiguredNetworks(
2498                        Binder.getCallingUid(), mWifiStateMachineChannel);
2499                if (networks != null) {
2500                    for (WifiConfiguration config : networks) {
2501                        removeNetwork(config.networkId);
2502                    }
2503                    saveConfiguration();
2504                }
2505            }
2506        }
2507    }
2508
2509    /* private methods */
2510    static boolean logAndReturnFalse(String s) {
2511        Log.d(TAG, s);
2512        return false;
2513    }
2514
2515    public static boolean isValid(WifiConfiguration config) {
2516        String validity = checkValidity(config);
2517        return validity == null || logAndReturnFalse(validity);
2518    }
2519
2520    public static String checkValidity(WifiConfiguration config) {
2521        if (config.allowedKeyManagement == null)
2522            return "allowed kmgmt";
2523
2524        if (config.allowedKeyManagement.cardinality() > 1) {
2525            if (config.allowedKeyManagement.cardinality() != 2) {
2526                return "cardinality != 2";
2527            }
2528            if (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP)) {
2529                return "not WPA_EAP";
2530            }
2531            if ((!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X))
2532                    && (!config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK))) {
2533                return "not PSK or 8021X";
2534            }
2535        }
2536        if (config.getIpAssignment() == IpConfiguration.IpAssignment.STATIC) {
2537            StaticIpConfiguration staticIpConf = config.getStaticIpConfiguration();
2538            if (staticIpConf == null) {
2539                return "null StaticIpConfiguration";
2540            }
2541            if (staticIpConf.ipAddress == null) {
2542                return "null static ip Address";
2543            }
2544        }
2545        return null;
2546    }
2547
2548    @Override
2549    public Network getCurrentNetwork() {
2550        enforceAccessPermission();
2551        mLog.info("getCurrentNetwork uid=%").c(Binder.getCallingUid()).flush();
2552        return mWifiStateMachine.getCurrentNetwork();
2553    }
2554
2555    public static String toHexString(String s) {
2556        if (s == null) {
2557            return "null";
2558        }
2559        StringBuilder sb = new StringBuilder();
2560        sb.append('\'').append(s).append('\'');
2561        for (int n = 0; n < s.length(); n++) {
2562            sb.append(String.format(" %02x", s.charAt(n) & 0xffff));
2563        }
2564        return sb.toString();
2565    }
2566
2567    public void hideCertFromUnaffiliatedUsers(String alias) {
2568        mCertManager.hideCertFromUnaffiliatedUsers(alias);
2569    }
2570
2571    public String[] listClientCertsForCurrentUser() {
2572        return mCertManager.listClientCertsForCurrentUser();
2573    }
2574
2575    /**
2576     * Enable/disable WifiConnectivityManager at runtime
2577     *
2578     * @param enabled true-enable; false-disable
2579     */
2580    @Override
2581    public void enableWifiConnectivityManager(boolean enabled) {
2582        enforceConnectivityInternalPermission();
2583        mLog.info("enableWifiConnectivityManager uid=% enabled=%")
2584                .c(Binder.getCallingUid())
2585                .c(enabled).flush();
2586        mWifiStateMachine.enableWifiConnectivityManager(enabled);
2587    }
2588
2589    /**
2590     * Retrieve the data to be backed to save the current state.
2591     *
2592     * @return  Raw byte stream of the data to be backed up.
2593     */
2594    @Override
2595    public byte[] retrieveBackupData() {
2596        enforceNetworkSettingsPermission();
2597        mLog.info("retrieveBackupData uid=%").c(Binder.getCallingUid()).flush();
2598        if (mWifiStateMachineChannel == null) {
2599            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2600            return null;
2601        }
2602
2603        Slog.d(TAG, "Retrieving backup data");
2604        List<WifiConfiguration> wifiConfigurations =
2605                mWifiStateMachine.syncGetPrivilegedConfiguredNetwork(mWifiStateMachineChannel);
2606        byte[] backupData =
2607                mWifiBackupRestore.retrieveBackupDataFromConfigurations(wifiConfigurations);
2608        Slog.d(TAG, "Retrieved backup data");
2609        return backupData;
2610    }
2611
2612    /**
2613     * Helper method to restore networks retrieved from backup data.
2614     *
2615     * @param configurations list of WifiConfiguration objects parsed from the backup data.
2616     */
2617    private void restoreNetworks(List<WifiConfiguration> configurations) {
2618        if (configurations == null) {
2619            Slog.e(TAG, "Backup data parse failed");
2620            return;
2621        }
2622        for (WifiConfiguration configuration : configurations) {
2623            int networkId = mWifiStateMachine.syncAddOrUpdateNetwork(
2624                    mWifiStateMachineChannel, configuration);
2625            if (networkId == WifiConfiguration.INVALID_NETWORK_ID) {
2626                Slog.e(TAG, "Restore network failed: " + configuration.configKey());
2627                continue;
2628            }
2629            // Enable all networks restored.
2630            mWifiStateMachine.syncEnableNetwork(mWifiStateMachineChannel, networkId, false);
2631        }
2632    }
2633
2634    /**
2635     * Restore state from the backed up data.
2636     *
2637     * @param data Raw byte stream of the backed up data.
2638     */
2639    @Override
2640    public void restoreBackupData(byte[] data) {
2641        enforceNetworkSettingsPermission();
2642        mLog.info("restoreBackupData uid=%").c(Binder.getCallingUid()).flush();
2643        if (mWifiStateMachineChannel == null) {
2644            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2645            return;
2646        }
2647
2648        Slog.d(TAG, "Restoring backup data");
2649        List<WifiConfiguration> wifiConfigurations =
2650                mWifiBackupRestore.retrieveConfigurationsFromBackupData(data);
2651        restoreNetworks(wifiConfigurations);
2652        Slog.d(TAG, "Restored backup data");
2653    }
2654
2655    /**
2656     * Restore state from the older supplicant back up data.
2657     * The old backup data was essentially a backup of wpa_supplicant.conf & ipconfig.txt file.
2658     *
2659     * @param supplicantData Raw byte stream of wpa_supplicant.conf
2660     * @param ipConfigData Raw byte stream of ipconfig.txt
2661     */
2662    public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
2663        enforceNetworkSettingsPermission();
2664        mLog.trace("restoreSupplicantBackupData uid=%").c(Binder.getCallingUid()).flush();
2665        if (mWifiStateMachineChannel == null) {
2666            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
2667            return;
2668        }
2669
2670        Slog.d(TAG, "Restoring supplicant backup data");
2671        List<WifiConfiguration> wifiConfigurations =
2672                mWifiBackupRestore.retrieveConfigurationsFromSupplicantBackupData(
2673                        supplicantData, ipConfigData);
2674        restoreNetworks(wifiConfigurations);
2675        Slog.d(TAG, "Restored supplicant backup data");
2676    }
2677}
2678