Add support for batched wifi scans.
bug:9301872 Change-Id: I5a7edfdbd2b78a65119d11acad491eae350c0870
This commit is contained in:
@@ -384,6 +384,8 @@ aidl_files := \
|
||||
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
|
||||
frameworks/base/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl \
|
||||
frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl \
|
||||
frameworks/base/wifi/java/android/net/wifi/BatchedScanSettings.aidl \
|
||||
frameworks/base/wifi/java/android/net/wifi/BatchedScanResult.aidl \
|
||||
|
||||
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
|
||||
$(gen): PRIVATE_SRC_FILES := $(aidl_files)
|
||||
|
||||
@@ -353,6 +353,9 @@
|
||||
Default value is 2 minutes. -->
|
||||
<integer translatable="false" name="config_wifi_driver_stop_delay">120000</integer>
|
||||
|
||||
<!-- Wifi driver supports batched scan -->
|
||||
<bool translatable="false" name="config_wifi_batched_scan_supported">false</bool>
|
||||
|
||||
<!-- Flag indicating whether the we should enable the automatic brightness in Settings.
|
||||
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
|
||||
<bool name="config_automatic_brightness_available">false</bool>
|
||||
|
||||
@@ -281,7 +281,8 @@
|
||||
<java-symbol type="bool" name="config_speed_up_audio_on_mt_calls" />
|
||||
<java-symbol type="bool" name="config_useFixedVolume" />
|
||||
<java-symbol type="bool" name="config_forceDefaultOrientation" />
|
||||
|
||||
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
|
||||
|
||||
<java-symbol type="integer" name="config_cursorWindowSize" />
|
||||
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
|
||||
<java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
|
||||
|
||||
@@ -25,18 +25,20 @@ import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.wifi.IWifiManager;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiStateMachine;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiWatchdogStateMachine;
|
||||
import android.net.DhcpInfo;
|
||||
import android.net.DhcpResults;
|
||||
import android.net.LinkAddress;
|
||||
import android.net.NetworkUtils;
|
||||
import android.net.RouteInfo;
|
||||
import android.net.wifi.IWifiManager;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.wifi.BatchedScanResult;
|
||||
import android.net.wifi.BatchedScanSettings;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiStateMachine;
|
||||
import android.net.wifi.WifiWatchdogStateMachine;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.Messenger;
|
||||
@@ -63,6 +65,7 @@ import java.io.PrintWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Inet4Address;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
@@ -121,6 +124,8 @@ public final class WifiService extends IWifiManager.Stub {
|
||||
/* Tracks the persisted states for wi-fi & airplane mode */
|
||||
final WifiSettingsStore mSettingsStore;
|
||||
|
||||
final boolean mBatchedScanSupported;
|
||||
|
||||
/**
|
||||
* Asynchronous channel to WifiStateMachine
|
||||
*/
|
||||
@@ -246,6 +251,9 @@ public final class WifiService extends IWifiManager.Stub {
|
||||
mWifiController = new WifiController(mContext, this, wifiThread.getLooper());
|
||||
mWifiController.start();
|
||||
|
||||
mBatchedScanSupported = mContext.getResources().getBoolean(
|
||||
R.bool.config_wifi_batched_scan_supported);
|
||||
|
||||
registerForScanModeChange();
|
||||
mContext.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@@ -314,6 +322,142 @@ public final class WifiService extends IWifiManager.Stub {
|
||||
mWifiStateMachine.startScan(Binder.getCallingUid(), workSource);
|
||||
}
|
||||
|
||||
private class BatchedScanRequest extends DeathRecipient {
|
||||
BatchedScanSettings settings;
|
||||
int uid;
|
||||
|
||||
BatchedScanRequest(BatchedScanSettings settings, IBinder binder, int uid) {
|
||||
super(0, null, binder, null);
|
||||
this.settings = settings;
|
||||
this.uid = uid;
|
||||
}
|
||||
public void binderDied() {
|
||||
stopBatchedScan(settings, mBinder);
|
||||
}
|
||||
public String toString() {
|
||||
return "BatchedScanRequest{settings=" + settings + ", binder=" + mBinder + "}";
|
||||
}
|
||||
}
|
||||
|
||||
private final List<BatchedScanRequest> mBatchedScanners = new ArrayList<BatchedScanRequest>();
|
||||
|
||||
public boolean isBatchedScanSupported() {
|
||||
return mBatchedScanSupported;
|
||||
}
|
||||
|
||||
/**
|
||||
* see {@link android.net.wifi.WifiManager#requestBatchedScan()}
|
||||
*/
|
||||
public boolean requestBatchedScan(BatchedScanSettings requested, IBinder binder) {
|
||||
enforceChangePermission();
|
||||
if (mBatchedScanSupported == false) return false;
|
||||
requested = new BatchedScanSettings(requested);
|
||||
if (requested.isInvalid()) return false;
|
||||
BatchedScanRequest r = new BatchedScanRequest(requested, binder, Binder.getCallingUid());
|
||||
synchronized(mBatchedScanners) {
|
||||
mBatchedScanners.add(r);
|
||||
resolveBatchedScannersLocked();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public List<BatchedScanResult> getBatchedScanResults(String callingPackage) {
|
||||
enforceAccessPermission();
|
||||
if (mBatchedScanSupported == false) return new ArrayList<BatchedScanResult>();
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
int uid = Binder.getCallingUid();
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
try {
|
||||
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
|
||||
!= AppOpsManager.MODE_ALLOWED) {
|
||||
return new ArrayList<BatchedScanResult>();
|
||||
}
|
||||
int currentUser = ActivityManager.getCurrentUser();
|
||||
if (userId != currentUser) {
|
||||
return new ArrayList<BatchedScanResult>();
|
||||
} else {
|
||||
return mWifiStateMachine.syncGetBatchedScanResultsList();
|
||||
}
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void stopBatchedScan(BatchedScanSettings settings, IBinder binder) {
|
||||
enforceChangePermission();
|
||||
if (mBatchedScanSupported == false) return;
|
||||
synchronized(mBatchedScanners) {
|
||||
BatchedScanRequest found = null;
|
||||
for (BatchedScanRequest r : mBatchedScanners) {
|
||||
if (r.mBinder.equals(binder) && r.settings.equals(settings)) {
|
||||
found = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found != null) {
|
||||
mBatchedScanners.remove(found);
|
||||
resolveBatchedScannersLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resolveBatchedScannersLocked() {
|
||||
BatchedScanSettings setting = new BatchedScanSettings();
|
||||
setting.scanIntervalSec = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
|
||||
int responsibleUid = 0;
|
||||
setting.channelSet = new ArrayList<String>();
|
||||
|
||||
if (mBatchedScanners.size() == 0) {
|
||||
mWifiStateMachine.setBatchedScanSettings(null, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
for (BatchedScanRequest r : mBatchedScanners) {
|
||||
BatchedScanSettings s = r.settings;
|
||||
if (s.maxScansPerBatch != BatchedScanSettings.UNSPECIFIED &&
|
||||
s.maxScansPerBatch < setting.maxScansPerBatch) {
|
||||
setting.maxScansPerBatch = s.maxScansPerBatch;
|
||||
responsibleUid = r.uid;
|
||||
}
|
||||
if (s.maxApPerScan != BatchedScanSettings.UNSPECIFIED &&
|
||||
s.maxApPerScan > setting.maxApPerScan) {
|
||||
setting.maxApPerScan = s.maxApPerScan;
|
||||
}
|
||||
if (s.scanIntervalSec != BatchedScanSettings.UNSPECIFIED &&
|
||||
s.scanIntervalSec < setting.scanIntervalSec) {
|
||||
setting.scanIntervalSec = s.scanIntervalSec;
|
||||
responsibleUid = r.uid;
|
||||
}
|
||||
if (s.maxApForDistance != BatchedScanSettings.UNSPECIFIED &&
|
||||
s.maxApForDistance > setting.maxApForDistance) {
|
||||
setting.maxApForDistance = s.maxApForDistance;
|
||||
}
|
||||
if (s.channelSet != null) {
|
||||
for (String i : s.channelSet) {
|
||||
if (setting.channelSet.contains(i) == false) setting.channelSet.add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (setting.channelSet.size() == 0) setting.channelSet = null;
|
||||
if (setting.scanIntervalSec < BatchedScanSettings.MIN_INTERVAL_SEC) {
|
||||
setting.scanIntervalSec = BatchedScanSettings.MIN_INTERVAL_SEC;
|
||||
}
|
||||
if (setting.maxScansPerBatch == BatchedScanSettings.UNSPECIFIED) {
|
||||
setting.maxScansPerBatch = BatchedScanSettings.DEFAULT_SCANS_PER_BATCH;
|
||||
}
|
||||
if (setting.maxApPerScan == BatchedScanSettings.UNSPECIFIED) {
|
||||
setting.maxApPerScan = BatchedScanSettings.DEFAULT_AP_PER_SCAN;
|
||||
}
|
||||
if (setting.scanIntervalSec == BatchedScanSettings.UNSPECIFIED) {
|
||||
setting.scanIntervalSec = BatchedScanSettings.DEFAULT_INTERVAL_SEC;
|
||||
}
|
||||
if (setting.maxApForDistance == BatchedScanSettings.UNSPECIFIED) {
|
||||
setting.maxApForDistance = BatchedScanSettings.DEFAULT_AP_FOR_DISTANCE;
|
||||
}
|
||||
mWifiStateMachine.setBatchedScanSettings(setting, responsibleUid);
|
||||
}
|
||||
|
||||
private void enforceAccessPermission() {
|
||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.ACCESS_WIFI_STATE,
|
||||
"WifiService");
|
||||
@@ -569,11 +713,11 @@ public final class WifiService extends IWifiManager.Stub {
|
||||
int userId = UserHandle.getCallingUserId();
|
||||
int uid = Binder.getCallingUid();
|
||||
long ident = Binder.clearCallingIdentity();
|
||||
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
|
||||
!= AppOpsManager.MODE_ALLOWED) {
|
||||
return new ArrayList<ScanResult>();
|
||||
}
|
||||
try {
|
||||
if (mAppOps.noteOp(AppOpsManager.OP_WIFI_SCAN, uid, callingPackage)
|
||||
!= AppOpsManager.MODE_ALLOWED) {
|
||||
return new ArrayList<ScanResult>();
|
||||
}
|
||||
int currentUser = ActivityManager.getCurrentUser();
|
||||
if (userId != currentUser) {
|
||||
return new ArrayList<ScanResult>();
|
||||
|
||||
19
wifi/java/android/net/wifi/BatchedScanResult.aidl
Normal file
19
wifi/java/android/net/wifi/BatchedScanResult.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2013, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
parcelable BatchedScanResult;
|
||||
94
wifi/java/android/net/wifi/BatchedScanResult.java
Normal file
94
wifi/java/android/net/wifi/BatchedScanResult.java
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Describes the Results of a batched set of wifi scans where the firmware performs many
|
||||
* scans and stores the timestamped results without waking the main processor each time.
|
||||
* @hide pending review
|
||||
*/
|
||||
public class BatchedScanResult implements Parcelable {
|
||||
private static final String TAG = "BatchedScanResult";
|
||||
|
||||
/** Inidcates this scan was interrupted and may only have partial results. */
|
||||
public boolean truncated;
|
||||
|
||||
/** The result of this particular scan. */
|
||||
public final List<ScanResult> scanResults = new ArrayList<ScanResult>();
|
||||
|
||||
|
||||
public BatchedScanResult() {
|
||||
}
|
||||
|
||||
public BatchedScanResult(BatchedScanResult source) {
|
||||
truncated = source.truncated;
|
||||
for (ScanResult s : source.scanResults) scanResults.add(new ScanResult(s));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
|
||||
sb.append("BatchedScanResult: ").
|
||||
append("truncated: ").append(String.valueOf(truncated)).
|
||||
append("scanResults: [");
|
||||
for (ScanResult s : scanResults) {
|
||||
sb.append(" <").append(s.toString()).append("> ");
|
||||
}
|
||||
sb.append(" ]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(truncated ? 1 : 0);
|
||||
dest.writeInt(scanResults.size());
|
||||
for (ScanResult s : scanResults) {
|
||||
s.writeToParcel(dest, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public static final Creator<BatchedScanResult> CREATOR =
|
||||
new Creator<BatchedScanResult>() {
|
||||
public BatchedScanResult createFromParcel(Parcel in) {
|
||||
BatchedScanResult result = new BatchedScanResult();
|
||||
result.truncated = (in.readInt() == 1);
|
||||
int count = in.readInt();
|
||||
while (count-- > 0) {
|
||||
result.scanResults.add(ScanResult.CREATOR.createFromParcel(in));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public BatchedScanResult[] newArray(int size) {
|
||||
return new BatchedScanResult[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
19
wifi/java/android/net/wifi/BatchedScanSettings.aidl
Normal file
19
wifi/java/android/net/wifi/BatchedScanSettings.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2013, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
parcelable BatchedScanSettings;
|
||||
226
wifi/java/android/net/wifi/BatchedScanSettings.java
Normal file
226
wifi/java/android/net/wifi/BatchedScanSettings.java
Normal file
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Describes the settings for batched wifi scans where the firmware performs many
|
||||
* scans and stores the timestamped results without waking the main processor each time.
|
||||
* This can give information over time with minimal battery impact.
|
||||
* @hide pending review
|
||||
*/
|
||||
public class BatchedScanSettings implements Parcelable {
|
||||
private static final String TAG = "BatchedScanSettings";
|
||||
|
||||
/** Used to indicate no preference for an int value */
|
||||
public final static int UNSPECIFIED = Integer.MAX_VALUE;
|
||||
|
||||
// TODO - make MIN/mAX dynamic and gservices adjustable.
|
||||
public final static int MIN_SCANS_PER_BATCH = 2;
|
||||
public final static int MAX_SCANS_PER_BATCH = 255;
|
||||
public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH;
|
||||
|
||||
public final static int MIN_AP_PER_SCAN = 2;
|
||||
public final static int MAX_AP_PER_SCAN = 255;
|
||||
public final static int DEFAULT_AP_PER_SCAN = 16;
|
||||
|
||||
public final static int MIN_INTERVAL_SEC = 0;
|
||||
public final static int MAX_INTERVAL_SEC = 3600;
|
||||
public final static int DEFAULT_INTERVAL_SEC = 30;
|
||||
|
||||
public final static int MIN_AP_FOR_DISTANCE = 0;
|
||||
public final static int MAX_AP_FOR_DISTANCE = MAX_AP_PER_SCAN;
|
||||
public final static int DEFAULT_AP_FOR_DISTANCE = 0;
|
||||
|
||||
|
||||
/** The expected number of scans per batch. Note that the firmware may drop scans
|
||||
* leading to fewer scans during the normal batch scan duration. This value need not
|
||||
* be specified (may be set to {@link UNSPECIFIED}) by the application and we will try
|
||||
* to scan as many times as the firmware can support. If another app requests fewer
|
||||
* scans per batch we will attempt to honor that.
|
||||
*/
|
||||
public int maxScansPerBatch;
|
||||
|
||||
/** The maximum desired AP listed per scan. Fewer AP may be returned if that's all
|
||||
* that the driver detected. If another application requests more AP per scan that
|
||||
* will take precedence. The if more channels are detected than we request, the APs
|
||||
* with the lowest signal strength will be dropped.
|
||||
*/
|
||||
public int maxApPerScan;
|
||||
|
||||
/** The channels used in the scan. If all channels should be used, {@code null} may be
|
||||
* specified. If another application requests more channels or all channels, that
|
||||
* will take precedence.
|
||||
*/
|
||||
public Collection<String> channelSet;
|
||||
|
||||
/** The time between the start of two sequential scans, in seconds. If another
|
||||
* application requests more frequent scans, that will take precedence. If this
|
||||
* value is less than the duration of a scan, the next scan should start immediately.
|
||||
*/
|
||||
public int scanIntervalSec;
|
||||
|
||||
/** The number of the best (strongest signal) APs for which the firmware will
|
||||
* attempt to get distance information (RTT). Not all firmware supports this
|
||||
* feature, so it may be ignored. If another application requests a greater
|
||||
* number, that will take precedence.
|
||||
*/
|
||||
public int maxApForDistance;
|
||||
|
||||
public BatchedScanSettings() {
|
||||
clear();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
maxScansPerBatch = UNSPECIFIED;
|
||||
maxApPerScan = UNSPECIFIED;
|
||||
channelSet = null;
|
||||
scanIntervalSec = UNSPECIFIED;
|
||||
maxApForDistance = UNSPECIFIED;
|
||||
}
|
||||
|
||||
public BatchedScanSettings(BatchedScanSettings source) {
|
||||
maxScansPerBatch = source.maxScansPerBatch;
|
||||
maxApPerScan = source.maxApPerScan;
|
||||
if (source.channelSet != null) {
|
||||
channelSet = new ArrayList(source.channelSet);
|
||||
}
|
||||
scanIntervalSec = source.scanIntervalSec;
|
||||
maxApForDistance = source.maxApForDistance;
|
||||
}
|
||||
|
||||
private boolean channelSetIsValid() {
|
||||
if (channelSet == null || channelSet.isEmpty()) return true;
|
||||
for (String channel : channelSet) {
|
||||
try {
|
||||
int i = Integer.parseInt(channel);
|
||||
if (i > 0 && i < 197) continue;
|
||||
} catch (NumberFormatException e) {}
|
||||
if (channel.equals("A") || channel.equals("B")) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/** @hide */
|
||||
public boolean isInvalid() {
|
||||
if (maxScansPerBatch != UNSPECIFIED && (maxScansPerBatch < MIN_SCANS_PER_BATCH ||
|
||||
maxScansPerBatch > MAX_SCANS_PER_BATCH)) return true;
|
||||
if (maxApPerScan != UNSPECIFIED && (maxApPerScan < MIN_AP_PER_SCAN ||
|
||||
maxApPerScan > MAX_AP_PER_SCAN)) return true;
|
||||
if (channelSetIsValid() == false) return true;
|
||||
if (scanIntervalSec != UNSPECIFIED && (scanIntervalSec < MIN_INTERVAL_SEC ||
|
||||
scanIntervalSec > MAX_INTERVAL_SEC)) return true;
|
||||
if (maxApForDistance != UNSPECIFIED && (maxApForDistance < MIN_AP_FOR_DISTANCE ||
|
||||
maxApForDistance > MAX_AP_FOR_DISTANCE)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof BatchedScanSettings == false) return false;
|
||||
BatchedScanSettings o = (BatchedScanSettings)obj;
|
||||
if (maxScansPerBatch != o.maxScansPerBatch ||
|
||||
maxApPerScan != o.maxApPerScan ||
|
||||
scanIntervalSec != o.scanIntervalSec ||
|
||||
maxApForDistance != o.maxApForDistance) return false;
|
||||
if (channelSet == null) {
|
||||
return (o.channelSet == null);
|
||||
}
|
||||
return channelSet.equals(o.channelSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return maxScansPerBatch +
|
||||
(maxApPerScan * 3) +
|
||||
(scanIntervalSec * 5) +
|
||||
(maxApForDistance * 7) +
|
||||
(channelSet.hashCode() * 11);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
String none = "<none>";
|
||||
|
||||
sb.append("BatchScanSettings [maxScansPerBatch: ").
|
||||
append(maxScansPerBatch == UNSPECIFIED ? none : maxScansPerBatch).
|
||||
append(", maxApPerScan: ").append(maxApPerScan == UNSPECIFIED? none : maxApPerScan).
|
||||
append(", scanIntervalSec: ").
|
||||
append(scanIntervalSec == UNSPECIFIED ? none : scanIntervalSec).
|
||||
append(", maxApForDistance: ").
|
||||
append(maxApForDistance == UNSPECIFIED ? none : maxApForDistance).
|
||||
append(", channelSet: ");
|
||||
if (channelSet == null) {
|
||||
sb.append("ALL");
|
||||
} else {
|
||||
sb.append("<");
|
||||
for (String channel : channelSet) {
|
||||
sb.append(" " + channel);
|
||||
}
|
||||
sb.append(">");
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(maxScansPerBatch);
|
||||
dest.writeInt(maxApPerScan);
|
||||
dest.writeInt(scanIntervalSec);
|
||||
dest.writeInt(maxApForDistance);
|
||||
dest.writeInt(channelSet == null ? 0 : channelSet.size());
|
||||
if (channelSet != null) {
|
||||
for (String channel : channelSet) dest.writeString(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
public static final Creator<BatchedScanSettings> CREATOR =
|
||||
new Creator<BatchedScanSettings>() {
|
||||
public BatchedScanSettings createFromParcel(Parcel in) {
|
||||
BatchedScanSettings settings = new BatchedScanSettings();
|
||||
settings.maxScansPerBatch = in.readInt();
|
||||
settings.maxApPerScan = in.readInt();
|
||||
settings.scanIntervalSec = in.readInt();
|
||||
settings.maxApForDistance = in.readInt();
|
||||
int channelCount = in.readInt();
|
||||
if (channelCount > 0) {
|
||||
settings.channelSet = new ArrayList(channelCount);
|
||||
while (channelCount-- > 0) {
|
||||
settings.channelSet.add(in.readString());
|
||||
}
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
public BatchedScanSettings[] newArray(int size) {
|
||||
return new BatchedScanSettings[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -16,8 +16,10 @@
|
||||
|
||||
package android.net.wifi;
|
||||
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.BatchedScanResult;
|
||||
import android.net.wifi.BatchedScanSettings;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.net.wifi.ScanResult;
|
||||
import android.net.DhcpInfo;
|
||||
|
||||
@@ -114,5 +116,13 @@ interface IWifiManager
|
||||
void enableTdls(String remoteIPAddress, boolean enable);
|
||||
|
||||
void enableTdlsWithMacAddress(String remoteMacAddress, boolean enable);
|
||||
|
||||
boolean requestBatchedScan(in BatchedScanSettings requested, IBinder binder);
|
||||
|
||||
void stopBatchedScan(in BatchedScanSettings requested, IBinder binder);
|
||||
|
||||
List<BatchedScanResult> getBatchedScanResults(String callingPackage);
|
||||
|
||||
boolean isBatchedScanSupported();
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,26 @@ public class ScanResult implements Parcelable {
|
||||
* Time Synchronization Function (tsf) timestamp in microseconds when
|
||||
* this result was last seen.
|
||||
*/
|
||||
public long timestamp;
|
||||
public long timestamp;
|
||||
|
||||
/**
|
||||
* The approximate distance to the AP in centimeter, if available. Else
|
||||
* {@link UNSPECIFIED}.
|
||||
* {@hide}
|
||||
*/
|
||||
public int distanceCm;
|
||||
|
||||
/**
|
||||
* The standard deviation of the distance to the AP, if available.
|
||||
* Else {@link UNSPECIFIED}.
|
||||
* {@hide}
|
||||
*/
|
||||
public int distanceSdCm;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
*/
|
||||
public final static int UNSPECIFIED = -1;
|
||||
|
||||
/** {@hide} */
|
||||
public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
|
||||
@@ -66,8 +85,23 @@ public class ScanResult implements Parcelable {
|
||||
this.level = level;
|
||||
this.frequency = frequency;
|
||||
this.timestamp = tsf;
|
||||
this.distanceCm = UNSPECIFIED;
|
||||
this.distanceSdCm = UNSPECIFIED;
|
||||
}
|
||||
|
||||
/** {@hide} */
|
||||
public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
|
||||
long tsf, int distCm, int distSdCm) {
|
||||
this.wifiSsid = wifiSsid;
|
||||
this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
|
||||
this.BSSID = BSSID;
|
||||
this.capabilities = caps;
|
||||
this.level = level;
|
||||
this.frequency = frequency;
|
||||
this.timestamp = tsf;
|
||||
this.distanceCm = distCm;
|
||||
this.distanceSdCm = distSdCm;
|
||||
}
|
||||
|
||||
/** copy constructor {@hide} */
|
||||
public ScanResult(ScanResult source) {
|
||||
@@ -79,6 +113,8 @@ public class ScanResult implements Parcelable {
|
||||
level = source.level;
|
||||
frequency = source.frequency;
|
||||
timestamp = source.timestamp;
|
||||
distanceCm = source.distanceCm;
|
||||
distanceSdCm = source.distanceSdCm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +136,11 @@ public class ScanResult implements Parcelable {
|
||||
append(", timestamp: ").
|
||||
append(timestamp);
|
||||
|
||||
sb.append(", distance: ").append((distanceCm != UNSPECIFIED ? distanceCm : "?")).
|
||||
append("(cm)");
|
||||
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
|
||||
append("(cm)");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@@ -121,6 +162,8 @@ public class ScanResult implements Parcelable {
|
||||
dest.writeInt(level);
|
||||
dest.writeInt(frequency);
|
||||
dest.writeLong(timestamp);
|
||||
dest.writeInt(distanceCm);
|
||||
dest.writeInt(distanceSdCm);
|
||||
}
|
||||
|
||||
/** Implement the Parcelable interface {@hide} */
|
||||
@@ -137,7 +180,9 @@ public class ScanResult implements Parcelable {
|
||||
in.readString(),
|
||||
in.readInt(),
|
||||
in.readInt(),
|
||||
in.readLong()
|
||||
in.readLong(),
|
||||
in.readInt(),
|
||||
in.readInt()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ import android.util.SparseArray;
|
||||
import java.net.InetAddress;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.AsyncChannel;
|
||||
import com.android.internal.util.Protocol;
|
||||
|
||||
@@ -364,6 +365,14 @@ public class WifiManager {
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
|
||||
/**
|
||||
* A batch of access point scans has been completed and the results areavailable.
|
||||
* Call {@link #getBatchedScanResults()} to obtain the results.
|
||||
* @hide pending review
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String BATCHED_SCAN_RESULTS_AVAILABLE_ACTION =
|
||||
"android.net.wifi.BATCHED_RESULTS";
|
||||
/**
|
||||
* The RSSI (signal strength) has changed.
|
||||
* @see #EXTRA_NEW_RSSI
|
||||
@@ -777,6 +786,59 @@ public class WifiManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Request a batched scan for access points. To end your requested batched scan,
|
||||
* call stopBatchedScan with the same Settings.
|
||||
*
|
||||
* If there are mulitple requests for batched scans, the more demanding settings will
|
||||
* take precidence.
|
||||
*
|
||||
* @param requested {@link BatchedScanSettings} the scan settings requested.
|
||||
* @return false on known error
|
||||
* @hide
|
||||
*/
|
||||
public boolean requestBatchedScan(BatchedScanSettings requested) {
|
||||
try {
|
||||
return mService.requestBatchedScan(requested, new Binder());
|
||||
} catch (RemoteException e) { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Batched Scan feature is supported.
|
||||
*
|
||||
* @return false if not supported.
|
||||
* @hide
|
||||
*/
|
||||
public boolean isBatchedScanSupported() {
|
||||
try {
|
||||
return mService.isBatchedScanSupported();
|
||||
} catch (RemoteException e) { return false; }
|
||||
}
|
||||
|
||||
/**
|
||||
* End a requested batch scan for this applicaiton. Note that batched scan may
|
||||
* still occur if other apps are using them.
|
||||
* @hide
|
||||
*/
|
||||
public void stopBatchedScan(BatchedScanSettings requested) {
|
||||
try {
|
||||
mService.stopBatchedScan(requested, new Binder());
|
||||
} catch (RemoteException e) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the latest batched scan result. This should be called immediately after
|
||||
* {@link BATCHED_SCAN_RESULTS_AVAILABLE_ACTION} is received.
|
||||
* @hide
|
||||
*/
|
||||
public List<BatchedScanResult> getBatchedScanResults() {
|
||||
try {
|
||||
return mService.getBatchedScanResults(mContext.getBasePackageName());
|
||||
} catch (RemoteException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return dynamic information about the current Wi-Fi connection, if any is active.
|
||||
* @return the Wi-Fi information, contained in {@link WifiInfo}.
|
||||
|
||||
@@ -216,6 +216,40 @@ public class WifiNative {
|
||||
return doStringCommand("BSS RANGE=" + sid + "- MASK=0x21987");
|
||||
}
|
||||
|
||||
/**
|
||||
* Format of command
|
||||
* DRIVER WLS_BATCHING SET SCAN_FRQ=x BESTN=y CHANNEL=<z, w, t> RTT=s
|
||||
* where x is an ascii representation of an integer number of seconds between scans
|
||||
* y is an ascii representation of an integer number of the max AP to remember per scan
|
||||
* z, w, t represent a 1..n size list of channel numbers and/or 'A', 'B' values
|
||||
* indicating entire ranges of channels
|
||||
* s is an ascii representation of an integer number of highest-strength AP
|
||||
* for which we'd like approximate distance reported
|
||||
*
|
||||
* The return value is an ascii integer representing a guess of the number of scans
|
||||
* the firmware can remember before it runs out of buffer space or -1 on error
|
||||
*/
|
||||
public String setBatchedScanSettings(BatchedScanSettings settings) {
|
||||
if (settings == null) return doStringCommand("DRIVER WLS_BATCHING STOP");
|
||||
String cmd = "DRIVER WLS_BATCHING SET SCAN_FRQ=" + settings.scanIntervalSec;
|
||||
if (settings.maxApPerScan != BatchedScanSettings.UNSPECIFIED) {
|
||||
cmd += " BESTN " + settings.maxApPerScan;
|
||||
}
|
||||
if (settings.channelSet != null && !settings.channelSet.isEmpty()) {
|
||||
cmd += " CHANNEL=<";
|
||||
for (String channel : settings.channelSet) cmd += " " + channel;
|
||||
cmd += ">";
|
||||
}
|
||||
if (settings.maxApForDistance != BatchedScanSettings.UNSPECIFIED) {
|
||||
cmd += " RTT=" + settings.maxApForDistance;
|
||||
}
|
||||
return doStringCommand(cmd);
|
||||
}
|
||||
|
||||
public String getBatchedScanResults() {
|
||||
return doStringCommand("DRIVER WLS_BATCHING GET");
|
||||
}
|
||||
|
||||
public boolean startDriver() {
|
||||
return doBooleanCommand("DRIVER START");
|
||||
}
|
||||
|
||||
@@ -122,6 +122,11 @@ public class WifiStateMachine extends StateMachine {
|
||||
private static final int SCAN_RESULT_CACHE_SIZE = 80;
|
||||
private final LruCache<String, ScanResult> mScanResultCache;
|
||||
|
||||
/* Batch scan results */
|
||||
private final List<BatchedScanResult> mBatchedScanResults =
|
||||
new ArrayList<BatchedScanResult>();
|
||||
private int mBatchedScanOwnerUid = UNKNOWN_SCAN_SOURCE;
|
||||
|
||||
/* Chipset supports background scan */
|
||||
private final boolean mBackgroundScanSupported;
|
||||
|
||||
@@ -210,6 +215,7 @@ public class WifiStateMachine extends StateMachine {
|
||||
private AlarmManager mAlarmManager;
|
||||
private PendingIntent mScanIntent;
|
||||
private PendingIntent mDriverStopIntent;
|
||||
private PendingIntent mBatchedScanIntervalIntent;
|
||||
|
||||
/* Tracks current frequency mode */
|
||||
private AtomicInteger mFrequencyBand = new AtomicInteger(WifiManager.WIFI_FREQUENCY_BAND_AUTO);
|
||||
@@ -355,6 +361,13 @@ public class WifiStateMachine extends StateMachine {
|
||||
|
||||
public static final int CMD_BOOT_COMPLETED = BASE + 134;
|
||||
|
||||
/* change the batch scan settings.
|
||||
* arg1 = responsible UID
|
||||
* obj = the new settings
|
||||
*/
|
||||
public static final int CMD_SET_BATCH_SCAN = BASE + 135;
|
||||
public static final int CMD_START_NEXT_BATCHED_SCAN = BASE + 136;
|
||||
|
||||
public static final int CONNECT_MODE = 1;
|
||||
public static final int SCAN_ONLY_MODE = 2;
|
||||
public static final int SCAN_ONLY_WITH_WIFI_OFF_MODE = 3;
|
||||
@@ -519,6 +532,8 @@ public class WifiStateMachine extends StateMachine {
|
||||
private static final String ACTION_DELAYED_DRIVER_STOP =
|
||||
"com.android.server.WifiManager.action.DELAYED_DRIVER_STOP";
|
||||
|
||||
private static final String ACTION_REFRESH_BATCHED_SCAN =
|
||||
"com.android.server.WifiManager.action.REFRESH_BATCHED_SCAN";
|
||||
/**
|
||||
* Keep track of whether WIFI is running.
|
||||
*/
|
||||
@@ -541,6 +556,9 @@ public class WifiStateMachine extends StateMachine {
|
||||
|
||||
private final IBatteryStats mBatteryStats;
|
||||
|
||||
private BatchedScanSettings mBatchedScanSettings = null;
|
||||
|
||||
|
||||
public WifiStateMachine(Context context, String wlanInterface) {
|
||||
super("WifiStateMachine");
|
||||
|
||||
@@ -577,6 +595,9 @@ public class WifiStateMachine extends StateMachine {
|
||||
Intent scanIntent = new Intent(ACTION_START_SCAN, null);
|
||||
mScanIntent = PendingIntent.getBroadcast(mContext, SCAN_REQUEST, scanIntent, 0);
|
||||
|
||||
Intent batchedIntent = new Intent(ACTION_REFRESH_BATCHED_SCAN, null);
|
||||
mBatchedScanIntervalIntent = PendingIntent.getBroadcast(mContext, 0, batchedIntent, 0);
|
||||
|
||||
mDefaultFrameworkScanIntervalMs = mContext.getResources().getInteger(
|
||||
R.integer.config_wifi_framework_scan_interval);
|
||||
|
||||
@@ -614,22 +635,25 @@ public class WifiStateMachine extends StateMachine {
|
||||
},
|
||||
new IntentFilter(ACTION_START_SCAN));
|
||||
|
||||
IntentFilter screenFilter = new IntentFilter();
|
||||
screenFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
BroadcastReceiver screenReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
filter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
filter.addAction(ACTION_REFRESH_BATCHED_SCAN);
|
||||
mContext.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (action.equals(Intent.ACTION_SCREEN_ON)) {
|
||||
handleScreenStateChanged(true);
|
||||
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
handleScreenStateChanged(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
mContext.registerReceiver(screenReceiver, screenFilter);
|
||||
if (action.equals(Intent.ACTION_SCREEN_ON)) {
|
||||
handleScreenStateChanged(true);
|
||||
} else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
|
||||
handleScreenStateChanged(false);
|
||||
} else if (action.equals(ACTION_REFRESH_BATCHED_SCAN)) {
|
||||
startNextBatchedScanAsync();
|
||||
}
|
||||
}
|
||||
}, filter);
|
||||
|
||||
mContext.registerReceiver(
|
||||
new BroadcastReceiver() {
|
||||
@@ -738,6 +762,269 @@ public class WifiStateMachine extends StateMachine {
|
||||
sendMessage(CMD_START_SCAN, callingUid, 0, workSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* start or stop batched scanning using the given settings
|
||||
*/
|
||||
public void setBatchedScanSettings(BatchedScanSettings settings, int callingUid) {
|
||||
sendMessage(CMD_SET_BATCH_SCAN, callingUid, 0, settings);
|
||||
}
|
||||
|
||||
public List<BatchedScanResult> syncGetBatchedScanResultsList() {
|
||||
synchronized (mBatchedScanResults) {
|
||||
List<BatchedScanResult> batchedScanList =
|
||||
new ArrayList<BatchedScanResult>(mBatchedScanResults.size());
|
||||
for(BatchedScanResult result: mBatchedScanResults) {
|
||||
batchedScanList.add(new BatchedScanResult(result));
|
||||
}
|
||||
return batchedScanList;
|
||||
}
|
||||
}
|
||||
|
||||
private void startBatchedScan() {
|
||||
// first grab any existing data
|
||||
retrieveBatchedScanData();
|
||||
|
||||
mAlarmManager.cancel(mBatchedScanIntervalIntent);
|
||||
|
||||
String scansExpected = mWifiNative.setBatchedScanSettings(mBatchedScanSettings);
|
||||
|
||||
try {
|
||||
int expected = Integer.parseInt(scansExpected);
|
||||
setNextBatchedAlarm(expected);
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Exception parsing WifiNative.setBatchedScanSettings response " + e);
|
||||
}
|
||||
}
|
||||
|
||||
// called from BroadcastListener
|
||||
private void startNextBatchedScanAsync() {
|
||||
sendMessage(CMD_START_NEXT_BATCHED_SCAN);
|
||||
}
|
||||
|
||||
private void startNextBatchedScan() {
|
||||
// first grab any existing data
|
||||
int nextCount = retrieveBatchedScanData();
|
||||
|
||||
setNextBatchedAlarm(nextCount);
|
||||
}
|
||||
|
||||
// return true if new/different
|
||||
private boolean recordBatchedScanSettings(BatchedScanSettings settings) {
|
||||
if (DBG) log("set batched scan to " + settings);
|
||||
if (settings != null) {
|
||||
// TODO - noteBatchedScanStart(message.arg1);
|
||||
if (settings.equals(mBatchedScanSettings)) return false;
|
||||
} else {
|
||||
if (mBatchedScanSettings == null) return false;
|
||||
// TODO - noteBatchedScanStop(message.arg1);
|
||||
}
|
||||
mBatchedScanSettings = settings;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void stopBatchedScan() {
|
||||
mAlarmManager.cancel(mBatchedScanIntervalIntent);
|
||||
retrieveBatchedScanData();
|
||||
mWifiNative.setBatchedScanSettings(null);
|
||||
}
|
||||
|
||||
private void setNextBatchedAlarm(int scansExpected) {
|
||||
|
||||
if (mBatchedScanSettings == null || scansExpected < 1) return;
|
||||
|
||||
if (mBatchedScanSettings.maxScansPerBatch < scansExpected) {
|
||||
scansExpected = mBatchedScanSettings.maxScansPerBatch;
|
||||
}
|
||||
|
||||
int secToFull = mBatchedScanSettings.scanIntervalSec;
|
||||
secToFull *= scansExpected;
|
||||
|
||||
int debugPeriod = SystemProperties.getInt("wifi.batchedScan.pollPeriod", 0);
|
||||
if (debugPeriod > 0) secToFull = debugPeriod;
|
||||
|
||||
// set the alarm to do the next poll. We set it a little short as we'd rather
|
||||
// wake up wearly than miss a scan due to buffer overflow
|
||||
mAlarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
|
||||
+ ((secToFull - (mBatchedScanSettings.scanIntervalSec / 2)) * 1000),
|
||||
mBatchedScanIntervalIntent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start reading new scan data
|
||||
* Data comes in as:
|
||||
* "scancount=5\n"
|
||||
* "nextcount=5\n"
|
||||
* "apcount=3\n"
|
||||
* "trunc\n" (optional)
|
||||
* "bssid=...\n"
|
||||
* "ssid=...\n"
|
||||
* "freq=...\n" (in Mhz)
|
||||
* "level=...\n"
|
||||
* "dist=...\n" (in cm)
|
||||
* "distsd=...\n" (standard deviation, in cm)
|
||||
* "===="
|
||||
* "bssid=...\n"
|
||||
* etc
|
||||
* "===="
|
||||
* "bssid=...\n"
|
||||
* etc
|
||||
* "%%%%"
|
||||
* "apcount=2\n"
|
||||
* "bssid=...\n"
|
||||
* etc
|
||||
* "%%%%
|
||||
* etc
|
||||
* "----"
|
||||
*/
|
||||
private int retrieveBatchedScanData() {
|
||||
String rawData = mWifiNative.getBatchedScanResults();
|
||||
if (rawData == null) {
|
||||
loge("Unexpected null BatchedScanResults");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nextCount = 0;
|
||||
int scanCount = 0;
|
||||
final String END_OF_SCAN = "====";
|
||||
final String END_OF_BATCH = "%%%%";
|
||||
final String END_OF_BATCHES = "----";
|
||||
final String SCANCOUNT = "scancount=";
|
||||
final String NEXTCOUNT = "nextcount=";
|
||||
final String TRUNCATED = "trunc";
|
||||
final String APCOUNT = "apcount=";
|
||||
final String AGE = "age=";
|
||||
final String DIST = "dist=";
|
||||
final String DISTSD = "distsd=";
|
||||
|
||||
String splitData[] = rawData.split("\n");
|
||||
int n = 0;
|
||||
if (splitData[n].startsWith(SCANCOUNT)) {
|
||||
try {
|
||||
scanCount = Integer.parseInt(splitData[n++].substring(SCANCOUNT.length()));
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
if (scanCount == 0) {
|
||||
loge("scanCount not found");
|
||||
return 0;
|
||||
}
|
||||
if (splitData[n].startsWith(NEXTCOUNT)) {
|
||||
try {
|
||||
nextCount = Integer.parseInt(splitData[n++].substring(NEXTCOUNT.length()));
|
||||
} catch (NumberFormatException e) {}
|
||||
}
|
||||
if (nextCount == 0) {
|
||||
loge("nextCount not found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(WifiManager.BATCHED_SCAN_RESULTS_AVAILABLE_ACTION);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
|
||||
synchronized (mBatchedScanResults) {
|
||||
mBatchedScanResults.clear();
|
||||
BatchedScanResult batchedScanResult = new BatchedScanResult();
|
||||
|
||||
String bssid = null;
|
||||
WifiSsid wifiSsid = null;
|
||||
int level = 0;
|
||||
int freq = 0;
|
||||
int dist, distSd;
|
||||
long tsf = 0;
|
||||
dist = distSd = ScanResult.UNSPECIFIED;
|
||||
long now = System.currentTimeMillis();
|
||||
|
||||
while (true) {
|
||||
while (n < splitData.length) {
|
||||
if (splitData[n].equals(END_OF_BATCHES)) {
|
||||
if (++n != splitData.length) {
|
||||
loge("didn't consume " + (splitData.length-n));
|
||||
}
|
||||
if (mBatchedScanResults.size() > 0) {
|
||||
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
return nextCount;
|
||||
}
|
||||
if ((splitData[n].equals(END_OF_SCAN)) || splitData[n].equals(END_OF_BATCH)) {
|
||||
if (bssid != null) {
|
||||
batchedScanResult.scanResults.add(new ScanResult(
|
||||
wifiSsid, bssid, "", level, freq, tsf, dist, distSd));
|
||||
wifiSsid = null;
|
||||
bssid = null;
|
||||
level = 0;
|
||||
freq = 0;
|
||||
tsf = 0;
|
||||
dist = distSd = ScanResult.UNSPECIFIED;
|
||||
}
|
||||
if (splitData[n].equals(END_OF_BATCH)) {
|
||||
if (batchedScanResult.scanResults.size() != 0) {
|
||||
mBatchedScanResults.add(batchedScanResult);
|
||||
batchedScanResult = new BatchedScanResult();
|
||||
} else {
|
||||
logd("Found empty batch");
|
||||
}
|
||||
}
|
||||
n++;
|
||||
} else if (splitData[n].equals(BSSID_STR)) {
|
||||
bssid = splitData[n++].substring(BSSID_STR.length());
|
||||
} else if (splitData[n].equals(FREQ_STR)) {
|
||||
try {
|
||||
freq = Integer.parseInt(splitData[n++].substring(FREQ_STR.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Invalid freqency: " + splitData[n-1]);
|
||||
freq = 0;
|
||||
}
|
||||
} else if (splitData[n].equals(AGE)) {
|
||||
try {
|
||||
tsf = now - Long.parseLong(splitData[n++].substring(AGE.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Invalid timestamp: " + splitData[n-1]);
|
||||
tsf = 0;
|
||||
}
|
||||
} else if (splitData[n].equals(SSID_STR)) {
|
||||
wifiSsid = WifiSsid.createFromAsciiEncoded(
|
||||
splitData[n++].substring(SSID_STR.length()));
|
||||
} else if (splitData[n].equals(LEVEL_STR)) {
|
||||
try {
|
||||
level = Integer.parseInt(splitData[n++].substring(LEVEL_STR.length()));
|
||||
if (level > 0) level -= 256;
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Invalid level: " + splitData[n-1]);
|
||||
level = 0;
|
||||
}
|
||||
} else if (splitData[n].equals(DIST)) {
|
||||
try {
|
||||
dist = Integer.parseInt(splitData[n++].substring(DIST.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Invalid distance: " + splitData[n-1]);
|
||||
dist = ScanResult.UNSPECIFIED;
|
||||
}
|
||||
} else if (splitData[n].equals(DISTSD)) {
|
||||
try {
|
||||
distSd = Integer.parseInt(splitData[n++].substring(DISTSD.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
loge("Invalid distanceSd: " + splitData[n-1]);
|
||||
distSd = ScanResult.UNSPECIFIED;
|
||||
}
|
||||
}
|
||||
}
|
||||
rawData = mWifiNative.getBatchedScanResults();
|
||||
if (rawData == null) {
|
||||
loge("Unexpected null BatchedScanResults");
|
||||
return nextCount;
|
||||
}
|
||||
splitData = rawData.split("\n");
|
||||
if (splitData.length == 0 || splitData[0].equals("ok")) {
|
||||
loge("batch scan results just ended!");
|
||||
if (mBatchedScanResults.size() > 0) {
|
||||
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
|
||||
}
|
||||
return nextCount;
|
||||
}
|
||||
n = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If workSource is not null, blame is given to it, otherwise blame is given to callingUid.
|
||||
private void noteScanStart(int callingUid, WorkSource workSource) {
|
||||
if (mScanWorkSource == null && (callingUid != UNKNOWN_SCAN_SOURCE || workSource != null)) {
|
||||
@@ -1979,6 +2266,12 @@ public class WifiStateMachine extends StateMachine {
|
||||
sendMessageAtFrontOfQueue(CMD_SET_COUNTRY_CODE, countryCode);
|
||||
}
|
||||
break;
|
||||
case CMD_SET_BATCH_SCAN:
|
||||
recordBatchedScanSettings((BatchedScanSettings)message.obj);
|
||||
break;
|
||||
case CMD_START_NEXT_BATCHED_SCAN:
|
||||
startNextBatchedScan();
|
||||
break;
|
||||
/* Discard */
|
||||
case CMD_START_SCAN:
|
||||
case CMD_START_SUPPLICANT:
|
||||
@@ -2472,6 +2765,10 @@ public class WifiStateMachine extends StateMachine {
|
||||
mWifiNative.stopFilteringMulticastV4Packets();
|
||||
}
|
||||
|
||||
if (mBatchedScanSettings != null) {
|
||||
startBatchedScan();
|
||||
}
|
||||
|
||||
if (mOperationalMode != CONNECT_MODE) {
|
||||
mWifiNative.disconnect();
|
||||
transitionTo(mScanModeState);
|
||||
@@ -2513,6 +2810,10 @@ public class WifiStateMachine extends StateMachine {
|
||||
noteScanStart(message.arg1, (WorkSource) message.obj);
|
||||
startScanNative(WifiNative.SCAN_WITH_CONNECTION_SETUP);
|
||||
break;
|
||||
case CMD_SET_BATCH_SCAN:
|
||||
recordBatchedScanSettings((BatchedScanSettings)message.obj);
|
||||
startBatchedScan();
|
||||
break;
|
||||
case CMD_SET_COUNTRY_CODE:
|
||||
String country = (String) message.obj;
|
||||
if (DBG) log("set country code " + country);
|
||||
@@ -2641,6 +2942,10 @@ public class WifiStateMachine extends StateMachine {
|
||||
updateBatteryWorkSource(null);
|
||||
mScanResults = new ArrayList<ScanResult>();
|
||||
|
||||
if (mBatchedScanSettings != null) {
|
||||
stopBatchedScan();
|
||||
}
|
||||
|
||||
final Intent intent = new Intent(WifiManager.WIFI_SCAN_AVAILABLE);
|
||||
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
|
||||
intent.putExtra(WifiManager.EXTRA_SCAN_AVAILABLE, WIFI_STATE_DISABLED);
|
||||
|
||||
Reference in New Issue
Block a user