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.
825 lines
26 KiB
Java
825 lines
26 KiB
Java
/*
|
|
* 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.
|
|
* 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.lowpan;
|
|
|
|
import android.annotation.NonNull;
|
|
import android.annotation.Nullable;
|
|
import android.content.Context;
|
|
import android.net.IpPrefix;
|
|
import android.net.LinkAddress;
|
|
import android.os.DeadObjectException;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.RemoteException;
|
|
import android.os.ServiceSpecificException;
|
|
import android.util.Log;
|
|
import java.util.HashMap;
|
|
|
|
/**
|
|
* Class for managing a specific Low-power Wireless Personal Area Network (LoWPAN) interface.
|
|
*
|
|
* @hide
|
|
*/
|
|
// @SystemApi
|
|
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 = ILowpanInterface.ROLE_DETACHED;
|
|
|
|
/** End-device role. End devices do not route traffic for other nodes. */
|
|
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 = ILowpanInterface.ROLE_ROUTER;
|
|
|
|
/**
|
|
* Sleepy End-Device role.
|
|
*
|
|
* <p>End devices with this role are nominally asleep, waking up periodically to check in with
|
|
* their parent to see if there are packets destined for them. Such devices are capable of
|
|
* 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 = ILowpanInterface.ROLE_SLEEPY_END_DEVICE;
|
|
|
|
/**
|
|
* Sleepy-router role.
|
|
*
|
|
* <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 = ILowpanInterface.ROLE_SLEEPY_ROUTER;
|
|
|
|
/** TODO: doc */
|
|
public static final String ROLE_LEADER = ILowpanInterface.ROLE_LEADER;
|
|
|
|
/** TODO: doc */
|
|
public static final String ROLE_COORDINATOR = ILowpanInterface.ROLE_COORDINATOR;
|
|
|
|
/**
|
|
* Offline state.
|
|
*
|
|
* <p>This is the initial state of the LoWPAN interface when the underlying driver starts. In
|
|
* this state the NCP is idle and not connected to any network.
|
|
*
|
|
* <p>This state can be explicitly entered by calling {@link #reset()}, {@link #leave()}, or
|
|
* <code>setUp(false)</code>, with the later two only working if we were not previously in the
|
|
* {@link #STATE_FAULT} state.
|
|
*
|
|
* @see #getState()
|
|
* @see #STATE_FAULT
|
|
*/
|
|
public static final String STATE_OFFLINE = ILowpanInterface.STATE_OFFLINE;
|
|
|
|
/**
|
|
* Commissioning state.
|
|
*
|
|
* <p>The interface enters this state after a call to {@link #startCommissioningSession()}. This
|
|
* state may only be entered directly from the {@link #STATE_OFFLINE} state.
|
|
*
|
|
* @see #startCommissioningSession()
|
|
* @see #getState()
|
|
* @hide
|
|
*/
|
|
public static final String STATE_COMMISSIONING = ILowpanInterface.STATE_COMMISSIONING;
|
|
|
|
/**
|
|
* Attaching state.
|
|
*
|
|
* <p>The interface enters this state when it starts the process of trying to find other nodes
|
|
* so that it can attach to any pre-existing network fragment, or when it is in the process of
|
|
* calculating the optimal values for unspecified parameters when forming a new network.
|
|
*
|
|
* <p>The interface may stay in this state for a prolonged period of time (or may spontaneously
|
|
* enter this state from {@link #STATE_ATTACHED}) if the underlying network technology is
|
|
* heirarchical (like ZigBeeIP) or if the device role is that of an "end-device" ({@link
|
|
* #ROLE_END_DEVICE} or {@link #ROLE_SLEEPY_END_DEVICE}). This is because such roles cannot
|
|
* create their own network fragments.
|
|
*
|
|
* @see #STATE_ATTACHED
|
|
* @see #getState()
|
|
*/
|
|
public static final String STATE_ATTACHING = ILowpanInterface.STATE_ATTACHING;
|
|
|
|
/**
|
|
* Attached state.
|
|
*
|
|
* <p>The interface enters this state from {@link #STATE_ATTACHING} once it is actively
|
|
* participating on a network fragment.
|
|
*
|
|
* @see #STATE_ATTACHING
|
|
* @see #getState()
|
|
*/
|
|
public static final String STATE_ATTACHED = ILowpanInterface.STATE_ATTACHED;
|
|
|
|
/**
|
|
* Fault state.
|
|
*
|
|
* <p>The interface will enter this state when the driver has detected some sort of problem from
|
|
* which it was not immediately able to recover.
|
|
*
|
|
* <p>This state can be entered spontaneously from any other state. Calling {@link #reset} will
|
|
* cause the device to return to the {@link #STATE_OFFLINE} state.
|
|
*
|
|
* @see #getState
|
|
* @see #STATE_OFFLINE
|
|
*/
|
|
public static final String STATE_FAULT = ILowpanInterface.STATE_FAULT;
|
|
|
|
/**
|
|
* Network type for Thread 1.x networks.
|
|
*
|
|
* @see android.net.lowpan.LowpanIdentity#getType
|
|
* @see #getLowpanIdentity
|
|
* @hide
|
|
*/
|
|
public static final String NETWORK_TYPE_THREAD_V1 = ILowpanInterface.NETWORK_TYPE_THREAD_V1;
|
|
|
|
public static final String EMPTY_PARTITION_ID = "";
|
|
|
|
/**
|
|
* Callback base class for LowpanInterface
|
|
*
|
|
* @hide
|
|
*/
|
|
// @SystemApi
|
|
public abstract static class Callback {
|
|
public void onConnectedChanged(boolean value) {}
|
|
|
|
public void onEnabledChanged(boolean value) {}
|
|
|
|
public void onUpChanged(boolean value) {}
|
|
|
|
public void onRoleChanged(@NonNull String value) {}
|
|
|
|
public void onStateChanged(@NonNull String state) {}
|
|
|
|
public void onLowpanIdentityChanged(@NonNull LowpanIdentity value) {}
|
|
|
|
public void onLinkNetworkAdded(IpPrefix prefix) {}
|
|
|
|
public void onLinkNetworkRemoved(IpPrefix prefix) {}
|
|
|
|
public void onLinkAddressAdded(LinkAddress address) {}
|
|
|
|
public void onLinkAddressRemoved(LinkAddress address) {}
|
|
}
|
|
|
|
private final ILowpanInterface mBinder;
|
|
private final Looper mLooper;
|
|
private final HashMap<Integer, ILowpanInterfaceListener> mListenerMap = new HashMap<>();
|
|
|
|
/**
|
|
* Create a new LowpanInterface instance. Applications will almost always want to use {@link
|
|
* LowpanManager#getInterface LowpanManager.getInterface()} instead of this.
|
|
*
|
|
* @param context the application context
|
|
* @param service the Binder interface
|
|
* @param looper the Binder interface
|
|
* @hide
|
|
*/
|
|
public LowpanInterface(Context context, ILowpanInterface service, Looper looper) {
|
|
/* We aren't currently using the context, but if we need
|
|
* it later on we can easily add it to the class.
|
|
*/
|
|
|
|
mBinder = service;
|
|
mLooper = looper;
|
|
}
|
|
|
|
/**
|
|
* Returns the ILowpanInterface object associated with this interface.
|
|
*
|
|
* @hide
|
|
*/
|
|
public ILowpanInterface getService() {
|
|
return mBinder;
|
|
}
|
|
|
|
// Public Actions
|
|
|
|
/**
|
|
* Form a new network with the given network information optional credential. Unspecified fields
|
|
* in the network information will be filled in with reasonable values. If the network
|
|
* credential is unspecified, one will be generated automatically.
|
|
*
|
|
* <p>This method will block until either the network was successfully formed or an error
|
|
* prevents the network form being formed.
|
|
*
|
|
* <p>Upon success, the interface will be up and attached to the newly formed network.
|
|
*
|
|
* @see #join(LowpanProvision)
|
|
*/
|
|
public void form(@NonNull LowpanProvision provision) throws LowpanException {
|
|
try {
|
|
mBinder.form(provision);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempts to join a new network with the given network information. This method will block
|
|
* until either the network was successfully joined or an error prevented the network from being
|
|
* formed. Upon success, the interface will be up and attached to the newly joined network.
|
|
*
|
|
* <p>Note that “joining” is distinct from “attaching”: Joining requires at least one other peer
|
|
* device to be present in order for the operation to complete successfully.
|
|
*/
|
|
public void join(@NonNull LowpanProvision provision) throws LowpanException {
|
|
try {
|
|
mBinder.join(provision);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attaches to the network described by identity and credential. This is similar to {@link
|
|
* #join}, except that (assuming the identity and credential are valid) it will always succeed
|
|
* and provision the interface, even if there are no peers nearby.
|
|
*
|
|
* <p>This method will block execution until the operation has completed.
|
|
*/
|
|
public void attach(@NonNull LowpanProvision provision) throws LowpanException {
|
|
try {
|
|
mBinder.attach(provision);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bring down the network interface and forget all non-volatile details about the current
|
|
* network.
|
|
*
|
|
* <p>This method will block execution until the operation has completed.
|
|
*/
|
|
public void leave() throws LowpanException {
|
|
try {
|
|
mBinder.leave();
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start a new commissioning session. Will fail if the interface is attached to a network or if
|
|
* the interface is disabled.
|
|
*/
|
|
public @NonNull LowpanCommissioningSession startCommissioningSession(
|
|
@NonNull LowpanBeaconInfo beaconInfo) throws LowpanException {
|
|
try {
|
|
mBinder.startCommissioningSession(beaconInfo);
|
|
|
|
return new LowpanCommissioningSession(mBinder, beaconInfo, mLooper);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reset this network interface as if it has been power cycled. Will bring the network interface
|
|
* down if it was previously up. Will not erase any non-volatile settings.
|
|
*
|
|
* <p>This method will block execution until the operation has completed.
|
|
*
|
|
* @hide
|
|
*/
|
|
public void reset() throws LowpanException {
|
|
try {
|
|
mBinder.reset();
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
// Public Getters and Setters
|
|
|
|
/** Returns the name of this network interface. */
|
|
@NonNull
|
|
public String getName() {
|
|
try {
|
|
return mBinder.getName();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return "";
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates if the interface is enabled or disabled.
|
|
*
|
|
* @see #setEnabled
|
|
* @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
|
|
*/
|
|
public boolean isEnabled() {
|
|
try {
|
|
return mBinder.isEnabled();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return false;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enables or disables the LoWPAN interface. When disabled, the interface is put into a
|
|
* low-power state and all commands that require the NCP to be queried will fail with {@link
|
|
* android.net.lowpan.LowpanException#LOWPAN_DISABLED}.
|
|
*
|
|
* @see #isEnabled
|
|
* @see android.net.lowpan.LowpanException#LOWPAN_DISABLED
|
|
* @hide
|
|
*/
|
|
public void setEnabled(boolean enabled) throws LowpanException {
|
|
try {
|
|
mBinder.setEnabled(enabled);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates if the network interface is up or down.
|
|
*
|
|
* @hide
|
|
*/
|
|
public boolean isUp() {
|
|
try {
|
|
return mBinder.isUp();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return false;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates if there is at least one peer in range.
|
|
*
|
|
* @return <code>true</code> if we have at least one other peer in range, <code>false</code>
|
|
* otherwise.
|
|
*/
|
|
public boolean isConnected() {
|
|
try {
|
|
return mBinder.isConnected();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return false;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Indicates if this interface is currently commissioned onto an existing network. If the
|
|
* interface is commissioned, the interface may be brought up using setUp().
|
|
*/
|
|
public boolean isCommissioned() {
|
|
try {
|
|
return mBinder.isCommissioned();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return false;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get interface state
|
|
*
|
|
* <h3>State Diagram</h3>
|
|
*
|
|
* <img src="LowpanInterface-1.png" />
|
|
*
|
|
* @return The current state of the interface.
|
|
* @see #STATE_OFFLINE
|
|
* @see #STATE_COMMISSIONING
|
|
* @see #STATE_ATTACHING
|
|
* @see #STATE_ATTACHED
|
|
* @see #STATE_FAULT
|
|
*/
|
|
public String getState() {
|
|
try {
|
|
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() {
|
|
try {
|
|
return mBinder.getLowpanIdentity();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return new LowpanIdentity();
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/** TODO: doc */
|
|
@NonNull
|
|
public String getRole() {
|
|
try {
|
|
return mBinder.getRole();
|
|
|
|
} catch (DeadObjectException x) {
|
|
return ROLE_DETACHED;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
/** TODO: doc */
|
|
@Nullable
|
|
public LowpanCredential getLowpanCredential() {
|
|
try {
|
|
return mBinder.getLowpanCredential();
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
|
|
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
|
|
|
|
/**
|
|
* Registers a subclass of {@link LowpanInterface.Callback} to receive events.
|
|
*
|
|
* @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
|
|
* @param handler If not <code>null</code>, events will be dispatched via the given handler
|
|
* object. If <code>null</code>, the thread upon which events will be dispatched is
|
|
* unspecified.
|
|
* @see #registerCallback(Callback)
|
|
* @see #unregisterCallback(Callback)
|
|
*/
|
|
public void registerCallback(@NonNull Callback cb, @Nullable Handler handler) {
|
|
ILowpanInterfaceListener.Stub listenerBinder =
|
|
new ILowpanInterfaceListener.Stub() {
|
|
private Handler mHandler;
|
|
|
|
{
|
|
if (handler != null) {
|
|
mHandler = handler;
|
|
} else if (mLooper != null) {
|
|
mHandler = new Handler(mLooper);
|
|
} else {
|
|
mHandler = new Handler();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onEnabledChanged(boolean value) {
|
|
mHandler.post(() -> cb.onEnabledChanged(value));
|
|
}
|
|
|
|
@Override
|
|
public void onConnectedChanged(boolean value) {
|
|
mHandler.post(() -> cb.onConnectedChanged(value));
|
|
}
|
|
|
|
@Override
|
|
public void onUpChanged(boolean value) {
|
|
mHandler.post(() -> cb.onUpChanged(value));
|
|
}
|
|
|
|
@Override
|
|
public void onRoleChanged(String value) {
|
|
mHandler.post(() -> cb.onRoleChanged(value));
|
|
}
|
|
|
|
@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 {
|
|
mBinder.addListener(listenerBinder);
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
|
|
synchronized (mListenerMap) {
|
|
mListenerMap.put(System.identityHashCode(cb), listenerBinder);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Registers a subclass of {@link LowpanInterface.Callback} to receive events.
|
|
*
|
|
* <p>The thread upon which events will be dispatched is unspecified.
|
|
*
|
|
* @param cb Subclass of {@link LowpanInterface.Callback} which will receive events.
|
|
* @see #registerCallback(Callback, Handler)
|
|
* @see #unregisterCallback(Callback)
|
|
*/
|
|
public void registerCallback(Callback cb) {
|
|
registerCallback(cb, null);
|
|
}
|
|
|
|
/**
|
|
* Unregisters a previously registered callback class.
|
|
*
|
|
* @param cb Subclass of {@link LowpanInterface.Callback} which was previously registered to
|
|
* receive events.
|
|
* @see #registerCallback(Callback, Handler)
|
|
* @see #registerCallback(Callback)
|
|
*/
|
|
public void unregisterCallback(Callback cb) {
|
|
int hashCode = System.identityHashCode(cb);
|
|
synchronized (mListenerMap) {
|
|
ILowpanInterfaceListener listenerBinder = mListenerMap.get(hashCode);
|
|
|
|
if (listenerBinder != null) {
|
|
mListenerMap.remove(hashCode);
|
|
|
|
try {
|
|
mBinder.removeListener(listenerBinder);
|
|
} catch (DeadObjectException x) {
|
|
// We ignore a dead object exception because that
|
|
// pretty clearly means our callback isn't registered.
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Active and Passive Scanning
|
|
|
|
/**
|
|
* Creates a new {@link android.net.lowpan.LowpanScanner} object for this interface.
|
|
*
|
|
* <p>This method allocates a new unique object for each call.
|
|
*
|
|
* @see android.net.lowpan.LowpanScanner
|
|
*/
|
|
public @NonNull LowpanScanner createScanner() {
|
|
return new LowpanScanner(mBinder);
|
|
}
|
|
|
|
// Route Management
|
|
|
|
/**
|
|
* Makes a copy of the internal list of LinkAddresses.
|
|
*
|
|
* @hide
|
|
*/
|
|
public LinkAddress[] getLinkAddresses() throws LowpanException {
|
|
try {
|
|
String[] linkAddressStrings = mBinder.getLinkAddresses();
|
|
LinkAddress[] ret = new LinkAddress[linkAddressStrings.length];
|
|
int i = 0;
|
|
for (String str : linkAddressStrings) {
|
|
ret[i++] = new LinkAddress(str);
|
|
}
|
|
return ret;
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Makes a copy of the internal list of networks reachable on via this link.
|
|
*
|
|
* @hide
|
|
*/
|
|
public IpPrefix[] getLinkNetworks() throws LowpanException {
|
|
try {
|
|
return mBinder.getLinkNetworks();
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Advertise the given IP prefix as an on-mesh prefix.
|
|
*
|
|
* @hide
|
|
*/
|
|
public void addOnMeshPrefix(IpPrefix prefix, int flags) throws LowpanException {
|
|
try {
|
|
mBinder.addOnMeshPrefix(prefix, flags);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an IP prefix previously advertised by this device from the list of advertised on-mesh
|
|
* prefixes.
|
|
*
|
|
* @hide
|
|
*/
|
|
public void removeOnMeshPrefix(IpPrefix prefix) {
|
|
try {
|
|
mBinder.removeOnMeshPrefix(prefix);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
// Catch and ignore all service exceptions
|
|
Log.e(TAG, x.toString());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Advertise this device to other devices on the mesh network as having a specific route to the
|
|
* given network. This device will then receive forwarded traffic for that network.
|
|
*
|
|
* @hide
|
|
*/
|
|
public void addExternalRoute(IpPrefix prefix, int flags) throws LowpanException {
|
|
try {
|
|
mBinder.addExternalRoute(prefix, flags);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
throw LowpanException.rethrowFromServiceSpecificException(x);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Revoke a previously advertised specific route to the given network.
|
|
*
|
|
* @hide
|
|
*/
|
|
public void removeExternalRoute(IpPrefix prefix) {
|
|
try {
|
|
mBinder.removeExternalRoute(prefix);
|
|
|
|
} catch (RemoteException x) {
|
|
throw x.rethrowAsRuntimeException();
|
|
|
|
} catch (ServiceSpecificException x) {
|
|
// Catch and ignore all service exceptions
|
|
Log.e(TAG, x.toString());
|
|
}
|
|
}
|
|
}
|