added basic RTT ranging info based on 802.11mc

This commit is contained in:
HappyZ 2017-12-19 22:30:11 -06:00
parent 3151cb14f3
commit f7677a661d
7 changed files with 1418 additions and 5 deletions

View File

@ -12,6 +12,9 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.LOCATION_HARDWARE" />
<application
android:allowBackup="true"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,291 @@
package de.plinzen.rttmanager;
import android.os.Build;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import java.lang.reflect.Array;
import java.lang.reflect.Proxy;
class RttManagerCompatUtil {
static final String CLASS_RESPONDER_CALLBACK = "android.net.wifi.RttManager$ResponderCallback";
static final String CLASS_RTT_LISTENER = "android.net.wifi.RttManager$RttListener";
static final String CLASS_RTT_PARAMS = "android.net.wifi.RttManager$RttParams";
private static final String TAG = RttManagerCompatUtil.class.getSimpleName();
static RttManagerCompat.Capabilities buildCapabilitiesFromNativeObject(
@NonNull final Object nativeCapabilities) {
final Class<?> nativeCapabilitiesClass = nativeCapabilities.getClass();
final RttManagerCompat.Capabilities capabilities = new RttManagerCompat.Capabilities();
capabilities.supportedType = readInt(nativeCapabilitiesClass, nativeCapabilities, "supportedType");
capabilities.supportedPeerType = readInt(nativeCapabilitiesClass, nativeCapabilities, "supportedPeerType");
return capabilities;
}
static Object buildNativeRttParams(
@Nullable final RttManagerCompat.RttParams[] params) throws ClassNotFoundException,
IllegalAccessException, InstantiationException {
if (params == null) {
return null;
}
final Class<?> nativeParamClass = Class.forName(CLASS_RTT_PARAMS);
final Object nativeParams = Array.newInstance(nativeParamClass, params.length);
for (int i = 0; i < params.length; i++) {
final RttManagerCompat.RttParams rttParam = params[i];
final Object nativeParam = nativeParamClass.newInstance();
setInt(nativeParamClass, nativeParam, "deviceType", rttParam.deviceType);
setInt(nativeParamClass, nativeParam, "requestType", rttParam.requestType);
setBoolean(nativeParamClass, nativeParam, "secure", rttParam.secure);
setObject(nativeParamClass, nativeParam, "bssid", rttParam.bssid);
setInt(nativeParamClass, nativeParam, "frequency", rttParam.frequency);
setInt(nativeParamClass, nativeParam, "channelWidth", rttParam.channelWidth);
setInt(nativeParamClass, nativeParam, "centerFreq0", rttParam.centerFreq0);
setInt(nativeParamClass, nativeParam, "centerFreq1", rttParam.centerFreq1);
setInt(nativeParamClass, nativeParam, "num_samples", rttParam.num_samples);
setInt(nativeParamClass, nativeParam, "num_retries", rttParam.num_retries);
setInt(nativeParamClass, nativeParam, "numberBurst", rttParam.numberBurst);
setInt(nativeParamClass, nativeParam, "interval", rttParam.interval);
setInt(nativeParamClass, nativeParam, "numSamplesPerBurst", rttParam.numSamplesPerBurst);
setInt(nativeParamClass, nativeParam, "numRetriesPerMeasurementFrame", rttParam
.numRetriesPerMeasurementFrame);
setInt(nativeParamClass, nativeParam, "numRetriesPerFTMR", rttParam.numRetriesPerFTMR);
setBoolean(nativeParamClass, nativeParam, "LCIRequest", rttParam.LCIRequest);
setBoolean(nativeParamClass, nativeParam, "LCRRequest", rttParam.LCRRequest);
setInt(nativeParamClass, nativeParam, "burstTimeout", rttParam.burstTimeout);
setInt(nativeParamClass, nativeParam, "preamble", rttParam.preamble);
setInt(nativeParamClass, nativeParam, "bandwidth", rttParam.bandwidth);
Array.set(nativeParams, i, nativeParam);
}
return nativeParams;
}
static RttManagerCompat.RttCapabilities buildRttCapabilitiesFromNativeObject(final Object nativeCapabilities) {
if (nativeCapabilities == null) {
return null;
}
final Class<?> nativeCapabilitiesClass = nativeCapabilities.getClass();
final RttManagerCompat.RttCapabilities capabilities = new RttManagerCompat.RttCapabilities();
capabilities.supportedType = readBoolean(nativeCapabilitiesClass, nativeCapabilities, "supportedType");
capabilities.supportedPeerType = readBoolean(nativeCapabilitiesClass, nativeCapabilities, "supportedPeerType");
capabilities.oneSidedRttSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities,
"oneSidedRttSupported");
capabilities.twoSided11McRttSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities,
"twoSided11McRttSupported");
capabilities.lciSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities, "lciSupported");
capabilities.lcrSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities, "lcrSupported");
capabilities.preambleSupported = readInt(nativeCapabilitiesClass, nativeCapabilities, "preambleSupported");
capabilities.bwSupported = readInt(nativeCapabilitiesClass, nativeCapabilities, "bwSupported");
capabilities.responderSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities,
"responderSupported");
// secureRttSupported and mcVersion were introduced with Android N
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
capabilities.secureRttSupported = readBoolean(nativeCapabilitiesClass, nativeCapabilities,
"secureRttSupported");
capabilities.mcVersion = readInt(nativeCapabilitiesClass, nativeCapabilities, "mcVersion");
// }
return capabilities;
}
static RttManagerCompat.ResponderCallbackWrapper wrapResponderCallback(
@Nullable final RttManagerCompat.ResponderCallback responderCallback) throws
ClassNotFoundException, IllegalAccessException, InstantiationException {
if (responderCallback == null) {
return null;
}
final Class<?> nativeParamClass = Class.forName(CLASS_RESPONDER_CALLBACK);
// TODO This does not work since ResponderCallback is an abstract class an no interface. Proxy only works on
// interfaces.
return (RttManagerCompat.ResponderCallbackWrapper) Proxy
.newProxyInstance(RttManagerCompat.ResponderCallbackWrapper.class.getClassLoader(), new
Class[]{RttManagerCompat.ResponderCallbackWrapper.class, nativeParamClass}, (proxy,
method, args) -> {
if ("onResponderEnabled".equals(method.getName())) {
responderCallback.onResponderEnabled(buildResponderConfigFromNativeObjects(args[0]));
} else if ("onResponderEnableFailure".equals(method.getName())) {
responderCallback.onResponderEnableFailure((int) args[0]);
} else if ("getResponderCallback".equals(method.getName())) {
return responderCallback;
}
return null;
});
}
static RttManagerCompat.RttListenerWrapper wrapRttListener(
@Nullable final RttManagerCompat.RttListener rttListener) throws
ClassNotFoundException, IllegalAccessException, InstantiationException {
if (rttListener == null) {
return null;
}
final Class<?> nativeParamClass = Class.forName(CLASS_RTT_LISTENER);
return (RttManagerCompat.RttListenerWrapper) Proxy
.newProxyInstance(RttManagerCompat.RttListenerWrapper.class.getClassLoader(), new
Class[]{RttManagerCompat
.RttListenerWrapper.class, nativeParamClass}, (proxy,
method, args) -> {
if ("onSuccess".equals(method.getName())) {
rttListener.onSuccess(buildRttResultFromNativeObjects(args[0]));
} else if ("onFailure".equals(method.getName())) {
rttListener.onFailure((int) args[0], (String) args[1]);
} else if ("onAborted".equals(method.getName())) {
rttListener.onAborted();
} else if ("getRttListenerCompat".equals(method.getName())) {
return rttListener;
}
return null;
});
}
private static RttManagerCompat.ResponderConfig buildResponderConfigFromNativeObjects(
@Nullable final Object nativeResult) {
if (nativeResult == null) {
return null;
}
final Class<?> nativeResultClass = nativeResult.getClass();
final RttManagerCompat.ResponderConfig config = new RttManagerCompat.ResponderConfig();
config.centerFreq0 = readInt(nativeResultClass, nativeResult, "centerFreq0");
config.centerFreq1 = readInt(nativeResultClass, nativeResult, "centerFreq1");
config.macAddress = readObject(nativeResultClass, nativeResult, "macAddress");
config.frequency = readInt(nativeResultClass, nativeResult, "frequency");
config.channelWidth = readInt(nativeResultClass, nativeResult, "channelWidth");
config.preamble = readInt(nativeResultClass, nativeResult, "preamble");
return config;
}
private static RttManagerCompat.RttResult[] buildRttResultFromNativeObjects(
@Nullable final Object nativeResults) throws NoSuchFieldException, IllegalAccessException {
if (nativeResults == null) {
return null;
}
final RttManagerCompat.RttResult[] results = new RttManagerCompat.RttResult[Array.getLength(nativeResults)];
for (int i = 0; i < results.length; i++) {
final Object nativeResult = Array.get(nativeResults, i);
final Class<?> nativeResultClass = nativeResult.getClass();
final RttManagerCompat.RttResult result = new RttManagerCompat.RttResult();
result.bssid = readObject(nativeResultClass, nativeResult, "bssid");
result.burstNumber = readInt(nativeResultClass, nativeResult, "burstNumber");
result.measurementFrameNumber = readInt(nativeResultClass, nativeResult, "measurementFrameNumber");
result.successMeasurementFrameNumber = readInt(nativeResultClass, nativeResult,
"successMeasurementFrameNumber");
result.frameNumberPerBurstPeer = readInt(nativeResultClass, nativeResult, "frameNumberPerBurstPeer");
result.status = readInt(nativeResultClass, nativeResult, "status");
result.requestType = readInt(nativeResultClass, nativeResult, "requestType");
result.measurementType = readInt(nativeResultClass, nativeResult, "measurementType");
result.retryAfterDuration = readInt(nativeResultClass, nativeResult, "retryAfterDuration");
result.ts = readLong(nativeResultClass, nativeResult, "ts");
result.rssi = readInt(nativeResultClass, nativeResult, "rssi");
result.rssiSpread = readInt(nativeResultClass, nativeResult, "rssiSpread");
result.txRate = readInt(nativeResultClass, nativeResult, "txRate");
result.rxRate = readInt(nativeResultClass, nativeResult, "rxRate");
result.rtt = readLong(nativeResultClass, nativeResult, "rtt");
result.rttStandardDeviation = readLong(nativeResultClass, nativeResult, "rttStandardDeviation");
result.rttSpread = readLong(nativeResultClass, nativeResult, "rttSpread");
result.distance = readInt(nativeResultClass, nativeResult, "distance");
result.distanceStandardDeviation = readInt(nativeResultClass, nativeResult, "distanceStandardDeviation");
result.distanceSpread = readInt(nativeResultClass, nativeResult, "distanceSpread");
result.burstDuration = readInt(nativeResultClass, nativeResult, "burstDuration");
result.negotiatedBurstNum = readInt(nativeResultClass, nativeResult, "negotiatedBurstNum");
result.secure = readBoolean(nativeResultClass, nativeResult, "secure");
result.LCI = buildWifiInformationElementFromNativeObjects(nativeResultClass.getField("LCI").get
(nativeResult));
result.LCR = buildWifiInformationElementFromNativeObjects(nativeResultClass.getField("LCR").get
(nativeResult));
results[i] = result;
}
return results;
}
private static RttManagerCompat.WifiInformationElement buildWifiInformationElementFromNativeObjects(
@Nullable final Object nativeResult) {
if (nativeResult == null) {
return null;
}
final Class<?> wifiInformationClass = nativeResult.getClass();
final RttManagerCompat.WifiInformationElement wifiInformation = new RttManagerCompat.WifiInformationElement();
wifiInformation.id = readByte(wifiInformationClass, nativeResult, "id");
wifiInformation.data = readObject(wifiInformationClass, nativeResult, "data");
return wifiInformation;
}
private static boolean readBoolean(@NonNull final Class<?> nativeClass, @NonNull final Object nativeObject,
@NonNull final String fieldName) {
try {
return nativeClass.getDeclaredField(fieldName).getBoolean(nativeObject);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
return false;
}
private static byte readByte(@NonNull final Class<?> nativeClass, @NonNull final Object nativeObject,
@NonNull final String fieldName) {
try {
return nativeClass.getDeclaredField(fieldName).getByte(nativeObject);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
return 0;
}
private static int readInt(@NonNull final Class<?> nativeClass, @NonNull final Object nativeObject,
@NonNull final String fieldName) {
try {
return nativeClass.getDeclaredField(fieldName).getInt(nativeObject);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
return 0;
}
private static long readLong(@NonNull final Class<?> nativeClass, @NonNull final Object nativeObject,
@NonNull final String fieldName) {
try {
return nativeClass.getDeclaredField(fieldName).getLong(nativeObject);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
return 0;
}
private static <T> T readObject(@NonNull final Class<?> nativeClass, @NonNull final Object nativeObject,
@NonNull final String fieldName) {
try {
return (T) nativeClass.getDeclaredField(fieldName).get(nativeObject);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
return null;
}
private static void setBoolean(@NonNull final Class<?> nativeParamClass, @NonNull final Object nativeObject,
@NonNull final String fieldName, @NonNull final boolean value) {
try {
nativeParamClass.getDeclaredField(fieldName).setBoolean(nativeObject, value);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
}
private static void setInt(@NonNull final Class<?> nativeParamClass, @NonNull final Object nativeObject,
@NonNull final String fieldName, @NonNull final int value) {
try {
nativeParamClass.getDeclaredField(fieldName).setInt(nativeObject, value);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
}
private static void setObject(@NonNull final Class<?> nativeParamClass, @NonNull final Object nativeObject,
@NonNull final String fieldName, @NonNull final Object value) {
try {
nativeParamClass.getDeclaredField(fieldName).set(nativeObject, value);
} catch (IllegalAccessException | NoSuchFieldException e) {
Log.e(TAG, e.getMessage(), e);
}
}
}

View File

@ -3,9 +3,12 @@ package edu.ucsb.cs.sandlab.offloadingdemo;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
@ -25,9 +28,12 @@ import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
class MainActivity extends Activity {
import de.plinzen.rttmanager.RttManagerCompat;
public class MainActivity extends Activity {
// unchanged stuff
protected static final String binaryFolderPath = "/data/local/tmp/";
protected static final String binary_tcpdump = "tcpdump";
@ -49,9 +55,10 @@ class MainActivity extends Activity {
// maintained variables
private Button btn_startTransmit, btn_startReceive, btn_measureBg;
private Button btn_setByte2send, btn_setRepeatTimes, btn_setTCPDumpInterface,
btn_clearStatus, btn_setLogFreq, btn_setOthers;
btn_clearStatus, btn_setLogFreq, btn_setOthers, btn_ranging;
private WifiManager wm;
private Intent intentSSLogger;
static boolean runOnce;
protected static int coreNum = 1;
protected static int perProcPID = -1;
protected static int UDPfinishTime = 0;
@ -582,6 +589,25 @@ class MainActivity extends Activity {
adb.create().show();
}
public void startRanging(ScanResult wifiConfig,
RttManagerCompat.RttListener rttListener) throws Throwable {
final RttManagerCompat.RttParams params = new RttManagerCompat.RttParams();
params.bssid = wifiConfig.BSSID;
params.requestType = RttManagerCompat.RTT_TYPE_TWO_SIDED;
params.frequency = wifiConfig.frequency;
params.centerFreq0 = wifiConfig.centerFreq0;
params.centerFreq1 = wifiConfig.centerFreq1;
params.channelWidth = wifiConfig.channelWidth;
RttManagerCompat rttManagerCompat = new RttManagerCompat(getApplicationContext());
final RttManagerCompat.RttCapabilities capabilities = rttManagerCompat.getRttCapabilities();
if (capabilities != null) {
params.LCIRequest = capabilities.lciSupported;
params.LCRRequest = capabilities.lcrSupported;
}
rttManagerCompat.startRanging(new RttManagerCompat.RttParams[]{params}, rttListener);
}
/**
* Initialize parameters etc.
*/
@ -653,14 +679,68 @@ class MainActivity extends Activity {
btn_setOthers = (Button) findViewById(R.id.btn_setOthers);
btn_setLogFreq = (Button) findViewById(R.id.btn_setLogFreq);
btn_clearStatus = (Button) findViewById(R.id.btn_clearStatus);
btn_ranging = (Button) findViewById(R.id.btn_ranging);
// grab WiFi service and check if wifi is enabled
wm = (WifiManager) this.getSystemService(WIFI_SERVICE);
wm = (WifiManager) this.getApplicationContext().getSystemService(WIFI_SERVICE);
isUsingWifi = wm.isWifiEnabled();
txt_results.append(
(isUsingWifi ? getString(R.string.stat_wifion) : getString(R.string.stat_wifioff)));
// click listener
btn_ranging.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isUsingWifi) return;
wm.startScan();
Log.d("ScanResult", "Start scanning");
runOnce = false;
BroadcastReceiver my_recv = new BroadcastReceiver() {
@Override
public void onReceive(Context c, Intent intent) {
if (runOnce) return;
List<ScanResult> results = wm.getScanResults();
if (results.isEmpty()) {
Log.d("ScanResult", "result is empty");
return;
}
try{
startRanging(results.get(0), new RttManagerCompat.RttListener() {
@Override
public void onAborted() {
}
@Override
public void onFailure(int reason, String description) {
myHandler.post(new Runnable() {
@Override
public void run() {
txt_results.append("failed: " + description);
}
});
}
@Override
public void onSuccess(RttManagerCompat.RttResult[] results) {
myHandler.post(new Runnable() {
@Override
public void run() {
for (int i = 0; i < results.length; i++)
txt_results.append(results[i].toString() + "\n");
}
});
}
});
runOnce = true;
} catch (Throwable e) {}
}
};
registerReceiver(my_recv, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION));
}
});
btn_startTransmit.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -1031,7 +1111,7 @@ class MainActivity extends Activity {
}
@Override
protected void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initialization();

View File

@ -24,7 +24,7 @@ import java.util.ArrayList;
* Updated by yanzi on 01/27/2017
* support multiple cores now
*/
class SSLogger extends Service {
public class SSLogger extends Service {
private static final String TAG = "SSLogger";
private boolean isRunning = false;
private boolean isRunningPollingThread = false;

View File

@ -157,6 +157,14 @@
android:layout_height="match_parent"
android:text="@string/btn_clear"
android:textSize="16dp"/>
<Button
android:id="@+id/btn_ranging"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:text="@string/btn_ranging"
android:textSize="16dp"/>
</LinearLayout>
<!--</HorizontalScrollView>-->

View File

@ -1,5 +1,6 @@
<resources>
<string name="app_name">Offloading Demo</string>
<string name="btn_ranging">WiFi\nRanging</string>
<string name="btn_setbytes">Set\nBytes</string>
<string name="btn_setrepeat">Set\nRepeats</string>
<string name="btn_setuptcpdump">Setup\nTCPDump</string>