lowpan: AIDL refactor to no longer use property design pattern

After doing a considerable amount of thinking on the subject,
I decided that attempting to directly port wpantund's property-based
API over to Binder was a mistake, so this commit contains the required
changes to abandon that approach and go with a more traditional
Binder interface.

Bug: b/63708348
Change-Id: I685cd066fabe8470ef4bb456aea7d3bb515c3969
Test: Compiled and ran unit tests, manually confirmed lowpanctl
      and lowpan-service (with related changes) appeared to be
      working properly.
This commit is contained in:
Robert Quattlebaum
2017-07-14 12:18:39 -07:00
parent 865fdc75c3
commit 6cfc490ccd
8 changed files with 538 additions and 452 deletions

View File

@@ -16,103 +16,39 @@
package android.net.lowpan;
import android.net.IpPrefix;
import android.net.lowpan.ILowpanEnergyScanCallback;
import android.net.lowpan.ILowpanInterfaceListener;
import android.net.lowpan.ILowpanNetScanCallback;
import android.net.lowpan.ILowpanEnergyScanCallback;
import android.os.PersistableBundle;
import android.net.IpPrefix;
import android.net.lowpan.LowpanBeaconInfo;
import android.net.lowpan.LowpanChannelInfo;
import android.net.lowpan.LowpanCredential;
import android.net.lowpan.LowpanIdentity;
import android.net.lowpan.LowpanProvision;
/** {@hide} */
interface ILowpanInterface {
//////////////////////////////////////////////////////////////////////////
// Permission String Constants
/* These are here for the sake of C++ interface implementations. */
// These are here for the sake of C++ interface implementations.
const String PERM_ACCESS_LOWPAN_STATE = "android.permission.ACCESS_LOWPAN_STATE";
const String PERM_CHANGE_LOWPAN_STATE = "android.permission.CHANGE_LOWPAN_STATE";
const String PERM_READ_LOWPAN_CREDENTIAL = "android.permission.READ_LOWPAN_CREDENTIAL";
//////////////////////////////////////////////////////////////////////////
// Property Key Constants
/** Type: Boolean */
const String KEY_INTERFACE_ENABLED = "android.net.lowpan.property.INTERFACE_ENABLED";
/** Type: Boolean */
const String KEY_INTERFACE_UP = "android.net.lowpan.property.INTERFACE_UP";
/** Type: Boolean */
const String KEY_INTERFACE_COMMISSIONED = "android.net.lowpan.property.INTERFACE_COMMISSIONED";
/** Type: Boolean */
const String KEY_INTERFACE_CONNECTED = "android.net.lowpan.property.INTERFACE_CONNECTED";
/** Type: String */
const String KEY_INTERFACE_STATE = "android.net.lowpan.property.INTERFACE_STATE";
/** Type: String */
const String KEY_NETWORK_NAME = "android.net.lowpan.property.NETWORK_NAME";
/** Type: Integer */
const String KEY_NETWORK_TYPE = "android.net.lowpan.property.NETWORK_TYPE";
/** Type: Integer */
const String KEY_NETWORK_PANID = "android.net.lowpan.property.NETWORK_PANID";
/** Type: byte[] */
const String KEY_NETWORK_XPANID = "android.net.lowpan.property.NETWORK_XPANID";
/** Type: String */
const String KEY_NETWORK_ROLE = "android.net.lowpan.property.NETWORK_ROLE";
/** Type: byte[] */
const String KEY_NETWORK_MASTER_KEY = "android.net.lowpan.property.NETWORK_MASTER_KEY";
/** Type: Integer */
const String KEY_NETWORK_MASTER_KEY_INDEX
= "android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX";
/** Type: int[] */
const String KEY_SUPPORTED_CHANNELS = "android.net.lowpan.property.SUPPORTED_CHANNELS";
/** Type: Integer */
const String KEY_CHANNEL = "android.net.lowpan.property.CHANNEL";
/** Type: int[] */
/**
* Channel mask key.
* Used for setting a channel mask when starting a scan.
* Type: int[]
* */
const String KEY_CHANNEL_MASK = "android.net.lowpan.property.CHANNEL_MASK";
/** Type: Integer */
/**
* Max Transmit Power Key.
* Used for setting the maximum transmit power when starting a network scan.
* Type: Integer
* */
const String KEY_MAX_TX_POWER = "android.net.lowpan.property.MAX_TX_POWER";
/** Type: Integer */
const String KEY_RSSI = "android.net.lowpan.property.RSSI";
/** Type: Integer */
const String KEY_LQI = "android.net.lowpan.property.LQI";
/** Type: byte[] */
const String KEY_BEACON_ADDRESS = "android.net.lowpan.property.BEACON_ORIGIN_ADDRESS";
/** Type: Boolean */
const String KEY_BEACON_CAN_ASSIST = "android.net.lowpan.property.BEACON_CAN_ASSIST";
/** Type: String */
const String DRIVER_VERSION = "android.net.lowpan.property.DRIVER_VERSION";
/** Type: String */
const String NCP_VERSION = "android.net.lowpan.property.NCP_VERSION";
/** Type: byte[]
* @hide */
const String KEY_EXTENDED_ADDRESS = "android.net.lowpan.property.EXTENDED_ADDRESS";
/** Type: byte[]
* @hide */
const String KEY_MAC_ADDRESS = "android.net.lowpan.property.MAC_ADDRESS";
//////////////////////////////////////////////////////////////////////////
// Interface States
const String STATE_OFFLINE = "offline";
@@ -121,16 +57,26 @@ interface ILowpanInterface {
const String STATE_ATTACHED = "attached";
const String STATE_FAULT = "fault";
//////////////////////////////////////////////////////////////////////////
// Device Roles
const String ROLE_END_DEVICE = "end-device";
const String ROLE_ROUTER = "router";
const String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
const String ROLE_SLEEPY_ROUTER = "sleepy-router";
const String ROLE_UNKNOWN = "unknown";
const String ROLE_LEADER = "leader";
const String ROLE_COORDINATOR = "coordinator";
const String ROLE_DETACHED = "detached";
const String NETWORK_TYPE_UNKNOWN = "unknown";
/**
* Network type for Thread 1.x networks.
*
* @see android.net.lowpan.LowpanIdentity#getType
* @see #getLowpanIdentity
*/
const String NETWORK_TYPE_THREAD_V1 = "org.threadgroup.thread.v1";
//////////////////////////////////////////////////////////////////////////
// Service-Specific Error Code Constants
const int ERROR_UNSPECIFIED = 1;
@@ -149,25 +95,49 @@ interface ILowpanInterface {
const int ERROR_JOIN_FAILED_AT_AUTH = 14;
const int ERROR_FORM_FAILED_AT_SCAN = 15;
//////////////////////////////////////////////////////////////////////////
// Methods
@utf8InCpp String getName();
void join(in Map parameters);
void form(in Map parameters);
@utf8InCpp String getNcpVersion();
@utf8InCpp String getDriverVersion();
LowpanChannelInfo[] getSupportedChannels();
@utf8InCpp String[] getSupportedNetworkTypes();
byte[] getMacAddress();
boolean isEnabled();
void setEnabled(boolean enabled);
boolean isUp();
boolean isCommissioned();
boolean isConnected();
@utf8InCpp String getState();
@utf8InCpp String getRole();
@utf8InCpp String getPartitionId();
byte[] getExtendedAddress();
LowpanIdentity getLowpanIdentity();
LowpanCredential getLowpanCredential();
@utf8InCpp String[] getLinkAddresses();
IpPrefix[] getLinkNetworks();
void join(in LowpanProvision provision);
void form(in LowpanProvision provision);
void attach(in LowpanProvision provision);
void leave();
void reset();
void startCommissioningSession(in LowpanBeaconInfo beaconInfo);
void closeCommissioningSession();
oneway void sendToCommissioner(in byte[] packet);
void beginLowPower();
void pollForData();
oneway void pollForData();
oneway void onHostWake();
@utf8InCpp String[] getPropertyKeys();
Map getProperties(in @utf8InCpp String[] keys);
void setProperties(in Map properties);
void addListener(ILowpanInterfaceListener listener);
oneway void removeListener(ILowpanInterfaceListener listener);
@@ -177,14 +147,9 @@ interface ILowpanInterface {
void startEnergyScan(in Map properties, ILowpanEnergyScanCallback listener);
oneway void stopEnergyScan();
String[] copyLinkAddresses();
IpPrefix[] copyLinkNetworks();
void addOnMeshPrefix(in IpPrefix prefix, int flags);
oneway void removeOnMeshPrefix(in IpPrefix prefix);
void addExternalRoute(in IpPrefix prefix, int flags);
oneway void removeExternalRoute(in IpPrefix prefix);
@utf8InCpp String getPropertyAsString(@utf8InCpp String key);
}

View File

@@ -17,14 +17,29 @@
package android.net.lowpan;
import android.net.IpPrefix;
import android.net.lowpan.LowpanIdentity;
/** {@hide} */
interface ILowpanInterfaceListener {
oneway void onPropertiesChanged(in Map properties);
oneway void onEnabledChanged(boolean value);
oneway void onLinkNetworkAdded(in IpPrefix prefix);
oneway void onLinkNetworkRemoved(in IpPrefix prefix);
oneway void onConnectedChanged(boolean value);
oneway void onLinkAddressAdded(in String address);
oneway void onLinkAddressRemoved(in String address);
oneway void onUpChanged(boolean value);
oneway void onRoleChanged(@utf8InCpp String value);
oneway void onStateChanged(@utf8InCpp String value);
oneway void onLowpanIdentityChanged(in LowpanIdentity value);
oneway void onLinkNetworkAdded(in IpPrefix value);
oneway void onLinkNetworkRemoved(in IpPrefix value);
oneway void onLinkAddressAdded(@utf8InCpp String value);
oneway void onLinkAddressRemoved(@utf8InCpp String value);
oneway void onReceiveFromCommissioner(in byte[] packet);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2016 The Android Open Source Project
* Copyright (C) 2017 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.
@@ -16,8 +16,10 @@
package android.net.lowpan;
import android.net.lowpan.LowpanBeaconInfo;
/** {@hide} */
interface ILowpanNetScanCallback {
oneway void onNetScanBeacon(in Map parameters);
oneway void onNetScanBeacon(in LowpanBeaconInfo beacon);
oneway void onNetScanFinished();
}

View File

@@ -18,9 +18,11 @@ package android.net.lowpan;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.net.Network;
import android.net.IpPrefix;
import android.os.DeadObjectException;
import android.os.Handler;
import java.net.InetSocketAddress;
import android.os.Looper;
import android.os.RemoteException;
/**
* Commissioning Session.
@@ -31,8 +33,15 @@ import java.net.InetSocketAddress;
* @hide
*/
// @SystemApi
public abstract class LowpanCommissioningSession {
public LowpanCommissioningSession() {}
public class LowpanCommissioningSession {
private final ILowpanInterface mBinder;
private final LowpanBeaconInfo mBeaconInfo;
private final ILowpanInterfaceListener mInternalCallback = new InternalCallback();
private final Looper mLooper;
private Handler mHandler;
private Callback mCallback = null;
private volatile boolean mIsClosed = false;
/**
* Callback base class for {@link LowpanCommissioningSession}
@@ -40,34 +49,175 @@ public abstract class LowpanCommissioningSession {
* @hide
*/
// @SystemApi
public static abstract class Callback {
public abstract static class Callback {
public void onReceiveFromCommissioner(@NonNull byte[] packet) {};
public void onClosed() {};
}
private class InternalCallback extends ILowpanInterfaceListener.Stub {
@Override
public void onStateChanged(String value) {
if (!mIsClosed) {
switch (value) {
case ILowpanInterface.STATE_OFFLINE:
case ILowpanInterface.STATE_FAULT:
synchronized (LowpanCommissioningSession.this) {
lockedCleanup();
}
}
}
}
@Override
public void onReceiveFromCommissioner(byte[] packet) {
mHandler.post(
() -> {
synchronized (LowpanCommissioningSession.this) {
if (!mIsClosed && (mCallback != null)) {
mCallback.onReceiveFromCommissioner(packet);
}
}
});
}
// We ignore all other callbacks.
@Override
public void onEnabledChanged(boolean value) {}
@Override
public void onConnectedChanged(boolean value) {}
@Override
public void onUpChanged(boolean value) {}
@Override
public void onRoleChanged(String value) {}
@Override
public void onLowpanIdentityChanged(LowpanIdentity value) {}
@Override
public void onLinkNetworkAdded(IpPrefix value) {}
@Override
public void onLinkNetworkRemoved(IpPrefix value) {}
@Override
public void onLinkAddressAdded(String value) {}
@Override
public void onLinkAddressRemoved(String value) {}
}
LowpanCommissioningSession(
ILowpanInterface binder, LowpanBeaconInfo beaconInfo, Looper looper) {
mBinder = binder;
mBeaconInfo = beaconInfo;
mLooper = looper;
if (mLooper != null) {
mHandler = new Handler(mLooper);
} else {
mHandler = new Handler();
}
try {
mBinder.addListener(mInternalCallback);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
private void lockedCleanup() {
// Note: this method is only called from synchronized contexts.
if (!mIsClosed) {
try {
mBinder.removeListener(mInternalCallback);
} catch (DeadObjectException x) {
/* We don't care if we receive a DOE at this point.
* DOE is as good as success as far as we are concerned.
*/
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
if (mCallback != null) {
mHandler.post(() -> mCallback.onClosed());
}
}
mCallback = null;
mIsClosed = true;
}
/** TODO: doc */
@NonNull
public abstract LowpanBeaconInfo getBeaconInfo();
public LowpanBeaconInfo getBeaconInfo() {
return mBeaconInfo;
}
/** TODO: doc */
public abstract void sendToCommissioner(@NonNull byte[] packet);
public void sendToCommissioner(@NonNull byte[] packet) {
if (!mIsClosed) {
try {
mBinder.sendToCommissioner(packet);
} catch (DeadObjectException x) {
/* This method is a best-effort delivery.
* We don't care if we receive a DOE at this point.
*/
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
}
/** TODO: doc */
public abstract void setCallback(@Nullable Callback cb, @Nullable Handler handler);
public synchronized void setCallback(@Nullable Callback cb, @Nullable Handler handler) {
if (!mIsClosed) {
/* This class can be created with or without a default looper.
* Also, this method can be called with or without a specific
* handler. If a handler is specified, it is to always be used.
* Otherwise, if there was a Looper specified when this object
* was created, we create a new handle based on that looper.
* Otherwise we just create a default handler object. Since we
* don't really know how the previous handler was created, we
* end up always replacing it here. This isn't a huge problem
* because this method should be called infrequently.
*/
if (handler != null) {
mHandler = handler;
} else if (mLooper != null) {
mHandler = new Handler(mLooper);
} else {
mHandler = new Handler();
}
mCallback = cb;
}
}
/** TODO: doc */
public abstract void close();
public synchronized void close() {
if (!mIsClosed) {
try {
mBinder.closeCommissioningSession();
/**
* This method is largely for Nest Weave, as an alternative to {@link #sendToCommissioner()}
* and @{link Callback#onReceiveFromCommissioner()}.
*
* <p>When used with the Network instance obtained from getNetwork(), the caller can use the
* given InetSocketAddress to communicate with the commissioner using a UDP (or, under certain
* circumstances, TCP) socket.
*/
public abstract @Nullable InetSocketAddress getInetSocketAddress();
lockedCleanup();
public abstract @Nullable Network getNetwork();
} catch (DeadObjectException x) {
/* We don't care if we receive a DOE at this point.
* DOE is as good as success as far as we are concerned.
*/
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
}
}

View File

@@ -28,8 +28,6 @@ import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Class for managing a specific Low-power Wireless Personal Area Network (LoWPAN) interface.
@@ -41,13 +39,13 @@ public class LowpanInterface {
private static final String TAG = LowpanInterface.class.getSimpleName();
/** Detached role. The interface is not currently attached to a network. */
public static final String ROLE_DETACHED = "detached";
public static final String ROLE_DETACHED = ILowpanInterface.ROLE_DETACHED;
/** End-device role. End devices do not route traffic for other nodes. */
public static final String ROLE_END_DEVICE = "end-device";
public static final String ROLE_END_DEVICE = ILowpanInterface.ROLE_END_DEVICE;
/** Router role. Routers help route traffic around the mesh network. */
public static final String ROLE_ROUTER = "router";
public static final String ROLE_ROUTER = ILowpanInterface.ROLE_ROUTER;
/**
* Sleepy End-Device role.
@@ -57,7 +55,7 @@ public class LowpanInterface {
* extraordinarilly low power consumption, but packet latency can be on the order of dozens of
* seconds(depending on how the node is configured).
*/
public static final String ROLE_SLEEPY_END_DEVICE = "sleepy-end-device";
public static final String ROLE_SLEEPY_END_DEVICE = ILowpanInterface.ROLE_SLEEPY_END_DEVICE;
/**
* Sleepy-router role.
@@ -65,13 +63,13 @@ public class LowpanInterface {
* <p>Routers with this role are nominally asleep, waking up periodically to check in with other
* routers and their children.
*/
public static final String ROLE_SLEEPY_ROUTER = "sleepy-router";
public static final String ROLE_SLEEPY_ROUTER = ILowpanInterface.ROLE_SLEEPY_ROUTER;
/** TODO: doc */
public static final String ROLE_LEADER = "leader";
public static final String ROLE_LEADER = ILowpanInterface.ROLE_LEADER;
/** TODO: doc */
public static final String ROLE_COORDINATOR = "coordinator";
public static final String ROLE_COORDINATOR = ILowpanInterface.ROLE_COORDINATOR;
/**
* Offline state.
@@ -86,7 +84,7 @@ public class LowpanInterface {
* @see #getState()
* @see #STATE_FAULT
*/
public static final String STATE_OFFLINE = "offline";
public static final String STATE_OFFLINE = ILowpanInterface.STATE_OFFLINE;
/**
* Commissioning state.
@@ -98,7 +96,7 @@ public class LowpanInterface {
* @see #getState()
* @hide
*/
public static final String STATE_COMMISSIONING = "commissioning";
public static final String STATE_COMMISSIONING = ILowpanInterface.STATE_COMMISSIONING;
/**
* Attaching state.
@@ -116,7 +114,7 @@ public class LowpanInterface {
* @see #STATE_ATTACHED
* @see #getState()
*/
public static final String STATE_ATTACHING = "attaching";
public static final String STATE_ATTACHING = ILowpanInterface.STATE_ATTACHING;
/**
* Attached state.
@@ -127,7 +125,7 @@ public class LowpanInterface {
* @see #STATE_ATTACHING
* @see #getState()
*/
public static final String STATE_ATTACHED = "attached";
public static final String STATE_ATTACHED = ILowpanInterface.STATE_ATTACHED;
/**
* Fault state.
@@ -141,7 +139,7 @@ public class LowpanInterface {
* @see #getState
* @see #STATE_OFFLINE
*/
public static final String STATE_FAULT = "fault";
public static final String STATE_FAULT = ILowpanInterface.STATE_FAULT;
/**
* Network type for Thread 1.x networks.
@@ -150,23 +148,9 @@ public class LowpanInterface {
* @see #getLowpanIdentity
* @hide
*/
public static final String NETWORK_TYPE_THREAD = "org.threadgroup.thread.v1";
public static final String NETWORK_TYPE_THREAD_V1 = ILowpanInterface.NETWORK_TYPE_THREAD_V1;
/**
* Network type for ZigBeeIP 1.x networks.
*
* @see android.net.lowpan.LowpanIdentity#getType
* @see #getLowpanIdentity
* @hide
*/
public static final String NETWORK_TYPE_ZIGBEE_IP = "org.zigbee.zigbeeip.v1";
private static final String NETWORK_PROPERTY_KEYS[] = {
LowpanProperties.KEY_NETWORK_NAME.getName(),
LowpanProperties.KEY_NETWORK_PANID.getName(),
LowpanProperties.KEY_NETWORK_XPANID.getName(),
LowpanProperties.KEY_CHANNEL.getName()
};
public static final String EMPTY_PARTITION_ID = "";
/**
* Callback base class for LowpanInterface
@@ -187,8 +171,13 @@ public class LowpanInterface {
public void onLowpanIdentityChanged(@NonNull LowpanIdentity value) {}
/** @hide */
public void onPropertiesChanged(@NonNull Map properties) {}
public void onLinkNetworkAdded(IpPrefix prefix) {}
public void onLinkNetworkRemoved(IpPrefix prefix) {}
public void onLinkAddressAdded(LinkAddress address) {}
public void onLinkAddressRemoved(LinkAddress address) {}
}
private final ILowpanInterface mBinder;
@@ -222,74 +211,6 @@ public class LowpanInterface {
return mBinder;
}
// Private Property Helpers
void setProperties(Map properties) throws LowpanException {
try {
mBinder.setProperties(properties);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
}
}
@NonNull
Map<String, Object> getProperties(String keys[]) throws LowpanException {
try {
return mBinder.getProperties(keys);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
}
}
/** @hide */
public <T> void setProperty(LowpanProperty<T> key, T value) throws LowpanException {
HashMap<String, T> prop = new HashMap<>();
prop.put(key.getName(), value);
setProperties(prop);
}
/** @hide */
@Nullable
public <T> T getProperty(LowpanProperty<T> key) throws LowpanException {
Map<String, Object> map = getProperties(new String[] {key.getName()});
if (map != null && !map.isEmpty()) {
// We know there is only one value.
return (T) map.values().iterator().next();
}
return null;
}
@Nullable
<T> String getPropertyAsString(LowpanProperty<T> key) throws LowpanException {
try {
return mBinder.getPropertyAsString(key.getName());
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
}
}
int getPropertyAsInt(LowpanProperty<Integer> key) throws LowpanException {
Integer value = getProperty(key);
return (value != null) ? value : 0;
}
boolean getPropertyAsBoolean(LowpanProperty<Boolean> key) throws LowpanException {
Boolean value = getProperty(key);
return (value != null) ? value : false;
}
// Public Actions
/**
@@ -306,15 +227,13 @@ public class LowpanInterface {
*/
public void form(@NonNull LowpanProvision provision) throws LowpanException {
try {
Map<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
mBinder.form(parameters);
mBinder.form(provision);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -328,15 +247,13 @@ public class LowpanInterface {
*/
public void join(@NonNull LowpanProvision provision) throws LowpanException {
try {
Map<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
mBinder.join(parameters);
mBinder.join(provision);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -348,13 +265,14 @@ public class LowpanInterface {
* <p>This method will block execution until the operation has completed.
*/
public void attach(@NonNull LowpanProvision provision) throws LowpanException {
if (ROLE_DETACHED.equals(getRole())) {
Map<String, Object> parameters = new HashMap();
provision.addToMap(parameters);
setProperties(parameters);
setUp(true);
} else {
throw new LowpanException(LowpanException.LOWPAN_ALREADY);
try {
mBinder.attach(provision);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -372,7 +290,7 @@ public class LowpanInterface {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -382,9 +300,17 @@ public class LowpanInterface {
*/
public @NonNull LowpanCommissioningSession startCommissioningSession(
@NonNull LowpanBeaconInfo beaconInfo) throws LowpanException {
try {
mBinder.startCommissioningSession(beaconInfo);
/* TODO: Implement startCommissioningSession */
throw new LowpanException(LowpanException.LOWPAN_FEATURE_NOT_SUPPORTED);
return new LowpanCommissioningSession(mBinder, beaconInfo, mLooper);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
/**
@@ -403,7 +329,7 @@ public class LowpanInterface {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -415,6 +341,9 @@ public class LowpanInterface {
try {
return mBinder.getName();
} catch (DeadObjectException x) {
return "";
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
@@ -428,9 +357,13 @@ public class LowpanInterface {
*/
public boolean isEnabled() {
try {
return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_ENABLED);
} catch (LowpanException x) {
return mBinder.isEnabled();
} catch (DeadObjectException x) {
return false;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
@@ -444,7 +377,15 @@ public class LowpanInterface {
* @hide
*/
public void setEnabled(boolean enabled) throws LowpanException {
setProperty(LowpanProperties.KEY_INTERFACE_ENABLED, enabled);
try {
mBinder.setEnabled(enabled);
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
/**
@@ -454,22 +395,14 @@ public class LowpanInterface {
*/
public boolean isUp() {
try {
return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_UP);
} catch (LowpanException x) {
return false;
}
}
return mBinder.isUp();
/**
* Bring up or shut down the network interface.
*
* <p>This method brings up or shuts down the network interface, attaching or (gracefully)
* detaching from the currently configured LoWPAN network as appropriate.
*
* @hide
*/
public void setUp(boolean interfaceUp) throws LowpanException {
setProperty(LowpanProperties.KEY_INTERFACE_UP, interfaceUp);
} catch (DeadObjectException x) {
return false;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
/**
@@ -480,9 +413,13 @@ public class LowpanInterface {
*/
public boolean isConnected() {
try {
return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_CONNECTED);
} catch (LowpanException x) {
return mBinder.isConnected();
} catch (DeadObjectException x) {
return false;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
@@ -492,9 +429,13 @@ public class LowpanInterface {
*/
public boolean isCommissioned() {
try {
return getPropertyAsBoolean(LowpanProperties.KEY_INTERFACE_COMMISSIONED);
} catch (LowpanException x) {
return mBinder.isCommissioned();
} catch (DeadObjectException x) {
return false;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
@@ -514,90 +455,89 @@ public class LowpanInterface {
*/
public String getState() {
try {
return getProperty(LowpanProperties.KEY_INTERFACE_STATE);
} catch (LowpanException x) {
Log.e(TAG, x.toString());
return mBinder.getState();
} catch (DeadObjectException x) {
return STATE_FAULT;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
/** Get network partition/fragment identifier. */
public String getPartitionId() {
try {
return mBinder.getPartitionId();
} catch (DeadObjectException x) {
return EMPTY_PARTITION_ID;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
/** TODO: doc */
public LowpanIdentity getLowpanIdentity() {
LowpanIdentity.Builder builder = new LowpanIdentity.Builder();
try {
builder.updateFromMap(getProperties(NETWORK_PROPERTY_KEYS));
} catch (LowpanException x) {
// We ignore all LoWPAN-specitic exceptions here.
return mBinder.getLowpanIdentity();
} catch (DeadObjectException x) {
return new LowpanIdentity();
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
return builder.build();
}
/**
* TODO: doc
*
* @hide
*/
public void setLowpanIdentity(LowpanIdentity network) throws LowpanException {
Map<String, Object> map = new HashMap();
LowpanIdentity.addToMap(map, network);
setProperties(map);
}
/** TODO: doc */
@NonNull
public String getRole() {
String role = null;
try {
role = getProperty(LowpanProperties.KEY_NETWORK_ROLE);
} catch (LowpanException x) {
// We ignore all LoWPAN-specitic exceptions here.
Log.e(TAG, x.toString());
}
return mBinder.getRole();
if (role == null) {
role = ROLE_DETACHED;
}
} catch (DeadObjectException x) {
return ROLE_DETACHED;
return role;
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
}
/** TODO: doc */
@Nullable
public LowpanCredential getLowpanCredential() {
LowpanCredential credential = null;
try {
Integer keyIndex = getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY_INDEX);
return mBinder.getLowpanCredential();
if (keyIndex == null) {
credential =
LowpanCredential.createMasterKey(
getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY));
} else {
credential =
LowpanCredential.createMasterKey(
getProperty(LowpanProperties.KEY_NETWORK_MASTER_KEY),
keyIndex.intValue());
}
} catch (LowpanException x) {
// We ignore all LoWPAN-specitic exceptions here.
Log.e(TAG, x.toString());
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
}
return credential;
}
/**
* TODO: doc
*
* @hide
*/
public void setLowpanCredential(LowpanCredential networkCredential) throws LowpanException {
Map<String, Object> map = new HashMap();
networkCredential.addToMap(map);
setProperties(map);
public @NonNull String[] getSupportedNetworkTypes() throws LowpanException {
try {
return mBinder.getSupportedNetworkTypes();
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
public @NonNull LowpanChannelInfo[] getSupportedChannels() throws LowpanException {
try {
return mBinder.getSupportedChannels();
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
// Listener Support
@@ -627,57 +567,80 @@ public class LowpanInterface {
}
}
@Override public void onPropertiesChanged(Map properties) {
Runnable runnable =
() -> {
for (String key : (Set<String>) properties.keySet()) {
Object value = properties.get(key);
switch (key) {
case ILowpanInterface.KEY_INTERFACE_ENABLED:
cb.onEnabledChanged(
((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_UP:
cb.onUpChanged(((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_CONNECTED:
cb.onConnectedChanged(
((Boolean) value).booleanValue());
break;
case ILowpanInterface.KEY_INTERFACE_STATE:
cb.onStateChanged((String) value);
break;
case ILowpanInterface.KEY_NETWORK_NAME:
case ILowpanInterface.KEY_NETWORK_PANID:
case ILowpanInterface.KEY_NETWORK_XPANID:
case ILowpanInterface.KEY_CHANNEL:
cb.onLowpanIdentityChanged(getLowpanIdentity());
break;
case ILowpanInterface.KEY_NETWORK_ROLE:
cb.onRoleChanged(value.toString());
break;
}
}
cb.onPropertiesChanged(properties);
};
mHandler.post(runnable);
@Override
public void onEnabledChanged(boolean value) {
mHandler.post(() -> cb.onEnabledChanged(value));
}
@Override public void onLinkNetworkAdded(IpPrefix prefix) {
// Support for this event isn't yet implemented.
@Override
public void onConnectedChanged(boolean value) {
mHandler.post(() -> cb.onConnectedChanged(value));
}
@Override public void onLinkNetworkRemoved(IpPrefix prefix) {
// Support for this event isn't yet implemented.
@Override
public void onUpChanged(boolean value) {
mHandler.post(() -> cb.onUpChanged(value));
}
@Override public void onLinkAddressAdded(String address) {
// Support for this event isn't yet implemented.
@Override
public void onRoleChanged(String value) {
mHandler.post(() -> cb.onRoleChanged(value));
}
@Override public void onLinkAddressRemoved(String address) {
// Support for this event isn't yet implemented.
@Override
public void onStateChanged(String value) {
mHandler.post(() -> cb.onStateChanged(value));
}
@Override
public void onLowpanIdentityChanged(LowpanIdentity value) {
mHandler.post(() -> cb.onLowpanIdentityChanged(value));
}
@Override
public void onLinkNetworkAdded(IpPrefix value) {
mHandler.post(() -> cb.onLinkNetworkAdded(value));
}
@Override
public void onLinkNetworkRemoved(IpPrefix value) {
mHandler.post(() -> cb.onLinkNetworkRemoved(value));
}
@Override
public void onLinkAddressAdded(String value) {
LinkAddress la;
try {
la = new LinkAddress(value);
} catch (IllegalArgumentException x) {
Log.e(
TAG,
"onLinkAddressAdded: Bad LinkAddress \"" + value + "\", " + x);
return;
}
mHandler.post(() -> cb.onLinkAddressAdded(la));
}
@Override
public void onLinkAddressRemoved(String value) {
LinkAddress la;
try {
la = new LinkAddress(value);
} catch (IllegalArgumentException x) {
Log.e(
TAG,
"onLinkAddressRemoved: Bad LinkAddress \""
+ value
+ "\", "
+ x);
return;
}
mHandler.post(() -> cb.onLinkAddressRemoved(la));
}
@Override
public void onReceiveFromCommissioner(byte[] packet) {
// This is only used by the LowpanCommissioningSession.
}
};
try {
@@ -752,9 +715,9 @@ public class LowpanInterface {
*
* @hide
*/
public LinkAddress[] copyLinkAddresses() throws LowpanException {
public LinkAddress[] getLinkAddresses() throws LowpanException {
try {
String[] linkAddressStrings = mBinder.copyLinkAddresses();
String[] linkAddressStrings = mBinder.getLinkAddresses();
LinkAddress[] ret = new LinkAddress[linkAddressStrings.length];
int i = 0;
for (String str : linkAddressStrings) {
@@ -766,7 +729,7 @@ public class LowpanInterface {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -775,15 +738,15 @@ public class LowpanInterface {
*
* @hide
*/
public IpPrefix[] copyLinkNetworks() throws LowpanException {
public IpPrefix[] getLinkNetworks() throws LowpanException {
try {
return mBinder.copyLinkNetworks();
return mBinder.getLinkNetworks();
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -800,7 +763,7 @@ public class LowpanInterface {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -837,7 +800,7 @@ public class LowpanInterface {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}

View File

@@ -16,74 +16,14 @@
package android.net.lowpan;
import android.net.IpPrefix;
import android.net.LinkAddress;
/** {@hide} */
public final class LowpanProperties {
public static final LowpanProperty<Boolean> KEY_INTERFACE_ENABLED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_ENABLED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_COMMISSIONED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_COMMISSIONED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_CONNECTED =
new LowpanStandardProperty(
"android.net.lowpan.property.INTERFACE_CONNECTED", Boolean.class);
public static final LowpanProperty<Boolean> KEY_INTERFACE_UP =
new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_UP", Boolean.class);
public static final LowpanProperty<String> KEY_INTERFACE_STATE =
new LowpanStandardProperty("android.net.lowpan.property.INTERFACE_STATE", String.class);
public static final LowpanProperty<String> KEY_NETWORK_NAME =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_NAME", Boolean.class);
public static final LowpanProperty<Integer> KEY_NETWORK_PANID =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_PANID", Integer.class);
public static final LowpanProperty<byte[]> KEY_NETWORK_XPANID =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_XPANID", byte[].class);
public static final LowpanProperty<byte[]> KEY_NETWORK_MASTER_KEY =
new LowpanStandardProperty(
"android.net.lowpan.property.NETWORK_MASTER_KEY", byte[].class);
public static final LowpanProperty<Integer> KEY_NETWORK_MASTER_KEY_INDEX =
new LowpanStandardProperty(
"android.net.lowpan.property.NETWORK_MASTER_KEY_INDEX", Integer.class);
public static final LowpanProperty<Integer> KEY_NETWORK_TYPE =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_TYPE", Integer.class);
public static final LowpanProperty<String> KEY_NETWORK_ROLE =
new LowpanStandardProperty("android.net.lowpan.property.NETWORK_ROLE", String.class);
public static final LowpanProperty<Integer> KEY_CHANNEL =
new LowpanStandardProperty("android.net.lowpan.property.CHANNEL", Integer.class);
public static final LowpanProperty<int[]> KEY_CHANNEL_MASK =
new LowpanStandardProperty("android.net.lowpan.property.CHANNEL_MASK", int[].class);
public static final LowpanProperty<Integer> KEY_MAX_TX_POWER =
new LowpanStandardProperty("android.net.lowpan.property.MAX_TX_POWER", Integer.class);
public static final LowpanProperty<Integer> KEY_RSSI =
new LowpanStandardProperty("android.net.lowpan.property.RSSI", Integer.class);
public static final LowpanProperty<Integer> KEY_LQI =
new LowpanStandardProperty("android.net.lowpan.property.LQI", Integer.class);
public static final LowpanProperty<byte[]> KEY_BEACON_ADDRESS =
new LowpanStandardProperty("android.net.lowpan.property.BEACON_ADDRESS", byte[].class);
public static final LowpanProperty<Boolean> KEY_BEACON_CAN_ASSIST =
new LowpanStandardProperty(
"android.net.lowpan.property.BEACON_CAN_ASSIST", Boolean.class);
public static final LowpanProperty<String> KEY_DRIVER_VERSION =
new LowpanStandardProperty("android.net.lowpan.property.DRIVER_VERSION", String.class);
public static final LowpanProperty<String> KEY_NCP_VERSION =
new LowpanStandardProperty("android.net.lowpan.property.NCP_VERSION", String.class);
/** @hide */
public static final LowpanProperty<byte[]> KEY_EXTENDED_ADDRESS =
new LowpanStandardProperty(
"android.net.lowpan.property.EXTENDED_ADDRESS", byte[].class);
/** @hide */
public static final LowpanProperty<byte[]> KEY_MAC_ADDRESS =
new LowpanStandardProperty("android.net.lowpan.property.MAC_ADDRESS", byte[].class);
/** @hide */
private LowpanProperties() {}

View File

@@ -21,7 +21,6 @@ import android.annotation.Nullable;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -37,7 +36,7 @@ import java.util.Map;
*/
// @SystemApi
public class LowpanScanner {
private static final String TAG = LowpanInterface.class.getSimpleName();
private static final String TAG = LowpanScanner.class.getSimpleName();
// Public Classes
@@ -174,7 +173,7 @@ public class LowpanScanner {
ILowpanNetScanCallback binderListener =
new ILowpanNetScanCallback.Stub() {
public void onNetScanBeacon(Map parameters) {
public void onNetScanBeacon(LowpanBeaconInfo beaconInfo) {
Callback callback;
Handler handler;
@@ -187,12 +186,7 @@ public class LowpanScanner {
return;
}
Runnable runnable =
() ->
callback.onNetScanBeacon(
new LowpanBeaconInfo.Builder()
.updateFromMap(parameters)
.build());
Runnable runnable = () -> callback.onNetScanBeacon(beaconInfo);
if (handler != null) {
handler.post(runnable);
@@ -231,7 +225,7 @@ public class LowpanScanner {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -246,9 +240,6 @@ public class LowpanScanner {
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
Log.e(TAG, x.toString());
}
}
@@ -315,7 +306,7 @@ public class LowpanScanner {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
throw LowpanException.rethrowAsLowpanException(x);
throw LowpanException.rethrowFromServiceSpecificException(x);
}
}
@@ -330,9 +321,6 @@ public class LowpanScanner {
} catch (RemoteException x) {
throw x.rethrowAsRuntimeException();
} catch (ServiceSpecificException x) {
Log.e(TAG, x.toString());
}
}
}

View File

@@ -20,6 +20,7 @@ import static org.mockito.Mockito.*;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.net.LinkAddress;
import android.os.Handler;
import android.os.IBinder;
import android.os.test.TestLooper;
@@ -86,4 +87,66 @@ public class LowpanInterfaceTest {
.onStateChanged(
argThat(stateString -> stateString.equals(LowpanInterface.STATE_OFFLINE)));
}
@Test
public void testLinkAddressCallback() throws Exception {
// Register our callback
mLowpanInterface.registerCallback(mLowpanInterfaceCallback);
// Verify a listener was added
verify(mLowpanInterfaceService)
.addListener(
argThat(
listener -> {
mInterfaceListener = listener;
return listener instanceof ILowpanInterfaceListener;
}));
final LinkAddress linkAddress = new LinkAddress("fe80::1/64");
// Change some properties
mInterfaceListener.onLinkAddressAdded(linkAddress.toString());
mTestLooper.dispatchAll();
// Verify that the property was changed
verify(mLowpanInterfaceCallback)
.onLinkAddressAdded(argThat(addr -> addr.equals(linkAddress)));
// Change some properties
mInterfaceListener.onLinkAddressRemoved(linkAddress.toString());
mTestLooper.dispatchAll();
// Verify that the property was changed
verify(mLowpanInterfaceCallback)
.onLinkAddressRemoved(argThat(addr -> addr.equals(linkAddress)));
}
@Test
public void testBogusLinkAddressCallback() throws Exception {
// Register our callback
mLowpanInterface.registerCallback(mLowpanInterfaceCallback);
// Verify a listener was added
verify(mLowpanInterfaceService)
.addListener(
argThat(
listener -> {
mInterfaceListener = listener;
return listener instanceof ILowpanInterfaceListener;
}));
// Change some properties
mInterfaceListener.onLinkAddressAdded("fe80:::1/640");
mTestLooper.dispatchAll();
// Verify that no callback was called.
verifyNoMoreInteractions(mLowpanInterfaceCallback);
// Change some properties
mInterfaceListener.onLinkAddressRemoved("fe80:::1/640");
mTestLooper.dispatchAll();
// Verify that no callback was called.
verifyNoMoreInteractions(mLowpanInterfaceCallback);
}
}