From 3c0a5570fdcc6a01e1a3a90337eebf3e4e6d19b8 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Wed, 29 Mar 2017 15:23:26 -0700 Subject: Initial commit of Android LoWPAN Manager Service Change-Id: I5fe40aa223c15110c753fe76a670e2fe8a01c5d0 Bug: b/33073713 --- .gitattributes | 3 + Android.mk | 19 + service/Android.mk | 29 + .../server/lowpan/LowpanInterfaceTracker.java | 591 +++++++++++++++++++++ .../com/android/server/lowpan/LowpanService.java | 45 ++ .../android/server/lowpan/LowpanServiceImpl.java | 275 ++++++++++ 6 files changed, 962 insertions(+) create mode 100644 .gitattributes create mode 100644 Android.mk create mode 100644 service/Android.mk create mode 100644 service/java/com/android/server/lowpan/LowpanInterfaceTracker.java create mode 100644 service/java/com/android/server/lowpan/LowpanService.java create mode 100644 service/java/com/android/server/lowpan/LowpanServiceImpl.java diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f0600ce --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.java text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof +*.aidl text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof +*.xml text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..7bd636b --- /dev/null +++ b/Android.mk @@ -0,0 +1,19 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/service/Android.mk b/service/Android.mk new file mode 100644 index 0000000..ff96a6c --- /dev/null +++ b/service/Android.mk @@ -0,0 +1,29 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := lowpan-service +LOCAL_MODULE_TAGS := +LOCAL_REQUIRED_MODULES := services +LOCAL_JAVA_LIBRARIES := services +LOCAL_SRC_FILES += java/com/android/server/lowpan/LowpanInterfaceTracker.java +LOCAL_SRC_FILES += java/com/android/server/lowpan/LowpanService.java +LOCAL_SRC_FILES += java/com/android/server/lowpan/LowpanServiceImpl.java +include $(BUILD_JAVA_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java new file mode 100644 index 0000000..32af169 --- /dev/null +++ b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java @@ -0,0 +1,591 @@ +/* + * 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 com.android.server.lowpan; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.NetworkAgent; +import android.net.NetworkCapabilities; +import android.net.NetworkFactory; +import android.net.NetworkInfo; +import android.net.NetworkInfo.DetailedState; +import android.net.lowpan.ILowpanInterface; +import android.net.lowpan.LowpanException; +import android.net.lowpan.LowpanInterface; +import android.net.lowpan.LowpanProperties; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; +import com.android.internal.util.HexDump; +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; +import com.android.server.net.NetlinkTracker; + +/** Tracks connectivity of a LoWPAN interface. */ +class LowpanInterfaceTracker extends StateMachine { + + //////////////////////////////////////////////////////////////////////////// + // Misc Constants + + /** Network type string for NetworkInfo */ + private static final String NETWORK_TYPE = "LoWPAN"; + + /** Tag used for logging */ + private static final String TAG = "LowpanInterfaceTracker"; + + /** + * Maximum network score for LoWPAN networks. + * + *

TODO: Research if 30 is an appropriate value. + */ + private static final int NETWORK_SCORE = 30; + + /** Internal debugging flag. */ + private static final boolean DBG = true; + + /** Number of state machine log records. */ + public static final short NUM_LOG_RECS_NORMAL = 100; + + //////////////////////////////////////////////////////////////////////////// + // Message Code Enumeration Constants + + /** The base for LoWPAN message codes */ + static final int BASE = Protocol.BASE_LOWPAN; + + static final int CMD_REGISTER = BASE + 1; + static final int CMD_UNREGISTER = BASE + 2; + static final int CMD_START_NETWORK = BASE + 3; + static final int CMD_STOP_NETWORK = BASE + 4; + static final int CMD_STATE_CHANGE = BASE + 5; + static final int CMD_LINK_PROPERTIES_CHANGE = BASE + 6; + static final int CMD_UNWANTED = BASE + 7; + + //////////////////////////////////////////////////////////////////////////// + // Services and interfaces + + ILowpanInterface mILowpanInterface; + private LowpanInterface mLowpanInterface; + private NetworkAgent mNetworkAgent; + private NetworkFactory mNetworkFactory; + private INetworkManagementService mNmService; + private final NetlinkTracker mNetlinkTracker; + + //////////////////////////////////////////////////////////////////////////// + // Instance Variables + + private String mInterfaceName; + private String mHwAddr; + private Context mContext; + private NetworkInfo mNetworkInfo; + private LinkProperties mLinkProperties; + private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities(); + private String mState = ""; + + //////////////////////////////////////////////////////////////////////////// + // State machine state instances + + final DefaultState mDefaultState = new DefaultState(); + final NormalState mNormalState = new NormalState(); + final InitState mInitState = new InitState(); + final OfflineState mOfflineState = new OfflineState(); + final CommissioningState mCommissioningState = new CommissioningState(); + final AttachingState mAttachingState = new AttachingState(); + final AttachedState mAttachedState = new AttachedState(); + final FaultState mFaultState = new FaultState(); + final ConnectedState mConnectedState = new ConnectedState(); + + //////////////////////////////////////////////////////////////////////////// + + private LocalLowpanCallback mLocalLowpanCallback = new LocalLowpanCallback(); + + //////////////////////////////////////////////////////////////////////////// + // Misc Private Classes + + private class LocalLowpanCallback extends LowpanInterface.Callback { + @Override + public void onEnabledChanged(boolean value) {} + + @Override + public void onUpChanged(boolean value) {} + + @Override + public void onConnectedChanged(boolean value) {} + + @Override + public void onStateChanged(@NonNull String state) { + LowpanInterfaceTracker.this.sendMessage(CMD_STATE_CHANGE, state); + } + } + + //////////////////////////////////////////////////////////////////////////// + // State Definitions + + class InitState extends State { + @Override + public void enter() {} + + @Override + public boolean processMessage(Message message) { + switch (message.what) { + case CMD_REGISTER: + if (DBG) { + Log.i(TAG, "CMD_REGISTER"); + } + transitionTo(mDefaultState); + break; + + default: + return NOT_HANDLED; + } + return HANDLED; + } + + @Override + public void exit() {} + } + + class DefaultState extends State { + @Override + public void enter() { + if (DBG) { + Log.i(TAG, "DefaultState.enter()"); + } + + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_NONE, 0, NETWORK_TYPE, ""); + mNetworkInfo.setIsAvailable(true); + + if (mNmService == null) { + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNmService = INetworkManagementService.Stub.asInterface(b); + } + + // Start tracking interface change events. + try { + mNmService.registerObserver(mNetlinkTracker); + } catch (RemoteException e) { + Log.e(TAG, "Could not register InterfaceObserver " + e); + } + + mLowpanInterface.registerCallback(mLocalLowpanCallback); + + mState = ""; + + sendMessage(CMD_STATE_CHANGE, mLowpanInterface.getState()); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = NOT_HANDLED; + + switch (message.what) { + case CMD_UNREGISTER: + transitionTo(mInitState); + retValue = HANDLED; + break; + + case CMD_START_NETWORK: + if (DBG) { + Log.i(TAG, "CMD_START_NETWORK"); + } + break; + + case CMD_STOP_NETWORK: + if (DBG) { + Log.i(TAG, "CMD_START_NETWORK"); + } + break; + + case CMD_STATE_CHANGE: + if (!mState.equals(message.obj)) { + if (DBG) { + Log.i( + TAG, + "LowpanInterface changed state from \"" + + mState + + "\" to \"" + + message.obj.toString() + + "\"."); + } + mState = (String) message.obj; + switch (mState) { + case LowpanInterface.STATE_OFFLINE: + transitionTo(mOfflineState); + break; + case LowpanInterface.STATE_COMMISSIONING: + transitionTo(mCommissioningState); + break; + case LowpanInterface.STATE_ATTACHING: + transitionTo(mAttachingState); + break; + case LowpanInterface.STATE_ATTACHED: + transitionTo(mConnectedState); + break; + case LowpanInterface.STATE_FAULT: + transitionTo(mFaultState); + break; + } + } + retValue = HANDLED; + break; + } + return retValue; + } + + @Override + public void exit() { + + try { + mNmService.unregisterObserver(mNetlinkTracker); + } catch (RemoteException x) { + Log.e(TAG, x.toString()); + } + + mLowpanInterface.unregisterCallback(mLocalLowpanCallback); + } + } + + class NormalState extends State { + @Override + public void enter() { + if (DBG) { + Log.i(TAG, "NormalState.enter()"); + } + + if (mHwAddr == null) { + byte[] hwAddr = null; + try { + hwAddr = mLowpanInterface.getProperty(LowpanProperties.KEY_MAC_ADDRESS); + } catch (LowpanException x) { + Log.e(TAG, x.toString()); + } + + if (hwAddr != null) { + mHwAddr = HexDump.toHexString(hwAddr); + } + } + + try { + mNmService.enableIpv6(mInterfaceName); + } catch (RemoteException x) { + Log.e( + TAG, + "Failed trying to enable IPv6 on " + mInterfaceName + ": " + x.toString()); + } + + mNetworkFactory.register(); + } + + @Override + public boolean processMessage(Message message) { + switch (message.what) { + case CMD_UNWANTED: + if (mNetworkAgent == message.obj) { + if (DBG) { + Log.i(TAG, "UNWANTED."); + } + // TODO: Figure out how to properly handle this. + try { + mLowpanInterface.leave(); + } catch (LowpanException x) { + Log.e(TAG, x.toString()); + } + shutdownNetworkAgent(); + } + break; + + case CMD_LINK_PROPERTIES_CHANGE: + mLinkProperties = (LinkProperties) message.obj; + if (DBG) { + Log.i(TAG, "Got LinkProperties: " + mLinkProperties); + } + if (mNetworkAgent != null) { + mNetworkAgent.sendLinkProperties(mLinkProperties); + } + break; + } + + return NOT_HANDLED; + } + + @Override + public void exit() { + shutdownNetworkAgent(); + mNetworkFactory.unregister(); + } + } + + class OfflineState extends State { + @Override + public void enter() { + shutdownNetworkAgent(); + mNetworkInfo.setIsAvailable(true); + } + + @Override + public boolean processMessage(Message message) { + return NOT_HANDLED; + } + + @Override + public void exit() {} + } + + class CommissioningState extends State { + @Override + public void enter() {} + + @Override + public boolean processMessage(Message message) { + return NOT_HANDLED; + } + + @Override + public void exit() {} + } + + class AttachingState extends State { + @Override + public void enter() { + try { + mNmService.enableIpv6(mInterfaceName); + } catch (RemoteException x) { + Log.e( + TAG, + "Failed trying to enable IPv6 on " + mInterfaceName + ": " + x.toString()); + } + + mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, mHwAddr); + mNetworkInfo.setIsAvailable(true); + bringUpNetworkAgent(); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + @Override + public boolean processMessage(Message message) { + return NOT_HANDLED; + } + + @Override + public void exit() {} + } + + class AttachedState extends State { + @Override + public void enter() { + mNetworkInfo.setIsAvailable(true); + } + + @Override + public boolean processMessage(Message message) { + switch (message.what) { + case CMD_STATE_CHANGE: + if (!mState.equals(message.obj)) { + if (!LowpanInterface.STATE_ATTACHED.equals(message.obj)) { + return NOT_HANDLED; + } + } + break; + + default: + return NOT_HANDLED; + } + return HANDLED; + } + + @Override + public void exit() { + mNetworkInfo.setIsAvailable(false); + } + } + + class ConnectedState extends State { + @Override + public void enter() { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); + + synchronized (mNetlinkTracker) { + mLinkProperties = mNetlinkTracker.getLinkProperties(); + } + + bringUpNetworkAgent(); + + mNetworkAgent.sendLinkProperties(mLinkProperties); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + mNetworkAgent.sendNetworkScore(NETWORK_SCORE); + } + + @Override + public boolean processMessage(Message message) { + return NOT_HANDLED; + } + + @Override + public void exit() { + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkScore(0); + } + } + } + + class FaultState extends State { + @Override + public void enter() {} + + @Override + public boolean processMessage(Message message) { + return NOT_HANDLED; + } + + @Override + public void exit() {} + } + + //////////////////////////////////////////////////////////////////////////// + + public LowpanInterfaceTracker( + ILowpanInterface lowpanInterface, Context context, Looper looper) { + super(TAG, looper); + + if (DBG) { + Log.i(TAG, "LowpanInterfaceTracker() begin"); + } + + setDbg(DBG); + setLogRecSize(NUM_LOG_RECS_NORMAL); + setLogOnlyTransitions(false); + + mILowpanInterface = lowpanInterface; + mLowpanInterface = LowpanInterface.from(mILowpanInterface); + mContext = context; + + mInterfaceName = mLowpanInterface.getName(); + + mLinkProperties = new LinkProperties(); + mLinkProperties.setInterfaceName(mInterfaceName); + + mNmService = + INetworkManagementService.Stub.asInterface( + ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + + // Initialize capabilities + mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_LOWPAN); + mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100); + mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100); + + // Things don't seem to work properly without this. TODO: Investigate. + mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + + // CHECKSTYLE:OFF IndentationCheck + addState(mInitState); + addState(mDefaultState); + addState(mFaultState, mDefaultState); + addState(mNormalState, mDefaultState); + addState(mOfflineState, mNormalState); + addState(mCommissioningState, mNormalState); + addState(mAttachingState, mNormalState); + addState(mAttachedState, mNormalState); + addState(mConnectedState, mAttachedState); + // CHECKSTYLE:ON IndentationCheck + + setInitialState(mInitState); + + mNetworkFactory = + new NetworkFactory(looper, context, NETWORK_TYPE, mNetworkCapabilities) { + @Override + protected void startNetwork() { + LowpanInterfaceTracker.this.sendMessage(CMD_START_NETWORK); + } + + @Override + protected void stopNetwork() { + LowpanInterfaceTracker.this.sendMessage(CMD_STOP_NETWORK); + } + }; + + mNetlinkTracker = + new NetlinkTracker( + mInterfaceName, + new NetlinkTracker.Callback() { + @Override + public void update() { + synchronized (mNetlinkTracker) { + sendMessage( + CMD_LINK_PROPERTIES_CHANGE, + mNetlinkTracker.getLinkProperties()); + } + } + }); + + start(); + + if (DBG) { + Log.i(TAG, "LowpanInterfaceTracker() end"); + } + } + + private void shutdownNetworkAgent() { + mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, mHwAddr); + mNetworkInfo.setIsAvailable(false); + + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkScore(0); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); + } + + mNetworkAgent = null; + } + + private void bringUpNetworkAgent() { + if (mNetworkAgent == null) { + mNetworkAgent = + new NetworkAgent( + mNetworkFactory.getLooper(), + mContext, + NETWORK_TYPE, + mNetworkInfo, + mNetworkCapabilities, + mLinkProperties, + NETWORK_SCORE) { + public void unwanted() { + LowpanInterfaceTracker.this.sendMessage(CMD_UNWANTED, this); + }; + }; + } + } + + public void register() { + if (DBG) { + Log.i(TAG, "register()"); + } + sendMessage(CMD_REGISTER); + } + + public void unregister() { + if (DBG) { + Log.i(TAG, "unregister()"); + } + sendMessage(CMD_UNREGISTER); + } +} diff --git a/service/java/com/android/server/lowpan/LowpanService.java b/service/java/com/android/server/lowpan/LowpanService.java new file mode 100644 index 0000000..910dff0 --- /dev/null +++ b/service/java/com/android/server/lowpan/LowpanService.java @@ -0,0 +1,45 @@ +/* + * 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 com.android.server.lowpan; + +import android.content.Context; +import android.net.lowpan.ILowpanManager; +import android.util.Log; +import com.android.server.SystemService; + +public final class LowpanService extends SystemService { + private static final String TAG = LowpanService.class.getSimpleName(); + private final LowpanServiceImpl mImpl; + + public LowpanService(Context context) { + super(context); + mImpl = new LowpanServiceImpl(context); + } + + @Override + public void onStart() { + Log.i(TAG, "Registering " + ILowpanManager.LOWPAN_SERVICE_NAME); + publishBinderService(ILowpanManager.LOWPAN_SERVICE_NAME, mImpl); + } + + @Override + public void onBootPhase(int phase) { + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + mImpl.checkAndStartLowpan(); + } + } +} diff --git a/service/java/com/android/server/lowpan/LowpanServiceImpl.java b/service/java/com/android/server/lowpan/LowpanServiceImpl.java new file mode 100644 index 0000000..be3eef6 --- /dev/null +++ b/service/java/com/android/server/lowpan/LowpanServiceImpl.java @@ -0,0 +1,275 @@ +/* + * 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 com.android.server.lowpan; + +import android.content.Context; +import android.net.lowpan.ILowpanInterface; +import android.net.lowpan.ILowpanManager; +import android.net.lowpan.ILowpanManagerListener; +import android.os.Binder; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.RemoteException; +import android.util.Log; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; + + +/** + * LowpanService handles remote LoWPAN operation requests by implementing the ILowpanManager + * interface. + * + * @hide + */ +public class LowpanServiceImpl extends ILowpanManager.Stub { + private static final String TAG = LowpanServiceImpl.class.getSimpleName(); + private final Set mListenerSet = new HashSet<>(); + private final Map mInterfaceMap = new HashMap<>(); + private final Context mContext; + private final HandlerThread mHandlerThread = new HandlerThread("LowpanServiceThread"); + private final AtomicBoolean mStarted = new AtomicBoolean(false); + + public LowpanServiceImpl(Context context) { + mContext = context; + } + + public Looper getLooper() { + Looper looper = mHandlerThread.getLooper(); + if (looper == null) { + mHandlerThread.start(); + looper = mHandlerThread.getLooper(); + } + + return looper; + } + + public void checkAndStartLowpan() { + synchronized (mInterfaceMap) { + if (mStarted.compareAndSet(false, true)) { + for (Map.Entry entry : mInterfaceMap.entrySet()) { + entry.getValue().register(); + } + } + } + + // TODO: Bring up any daemons(like wpantund)? + } + + private void enforceAccessPermission() { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.ACCESS_LOWPAN_STATE, "LowpanService"); + } + + private void enforceManagePermission() { + // TODO: Change to android.Manifest.permission.MANAGE_lowpanInterfaceS + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.CHANGE_LOWPAN_STATE, "LowpanService"); + } + + public ILowpanInterface getInterface(String name) { + ILowpanInterface iface = null; + + enforceAccessPermission(); + + synchronized (mInterfaceMap) { + LowpanInterfaceTracker tracker = mInterfaceMap.get(name); + if (tracker != null) { + iface = tracker.mILowpanInterface; + } + } + + return iface; + } + + public String[] getInterfaceList() { + enforceAccessPermission(); + synchronized (mInterfaceMap) { + return mInterfaceMap.keySet().toArray(new String[mInterfaceMap.size()]); + } + } + + private void onInterfaceRemoved(ILowpanInterface lowpanInterface, String name) { + Log.i(TAG, "Removed LoWPAN interface `" + name + "` (" + lowpanInterface.toString() + ")"); + synchronized (mListenerSet) { + for (ILowpanManagerListener listener : mListenerSet) { + try { + listener.onInterfaceRemoved(lowpanInterface); + } catch (RemoteException x) { + // Just skip. + Log.e(TAG, "Exception caught: " + x); + } + } + } + } + + private void onInterfaceAdded(ILowpanInterface lowpanInterface, String name) { + Log.i(TAG, "Added LoWPAN interface `" + name + "` (" + lowpanInterface.toString() + ")"); + synchronized (mListenerSet) { + for (ILowpanManagerListener listener : mListenerSet) { + try { + listener.onInterfaceAdded(lowpanInterface); + } catch (RemoteException x) { + // Just skip. + Log.e(TAG, "Exception caught: " + x); + } + } + } + } + + public void addInterface(ILowpanInterface lowpanInterface) { + enforceManagePermission(); + + final String name; + + try { + // We allow blocking calls to get the name of the interface. + Binder.allowBlocking(lowpanInterface.asBinder()); + + name = lowpanInterface.getName(); + lowpanInterface + .asBinder() + .linkToDeath( + new IBinder.DeathRecipient() { + @Override + public void binderDied() { + Log.w( + TAG, + "LoWPAN interface `" + + name + + "` (" + + lowpanInterface.toString() + + ") died."); + removeInterface(lowpanInterface); + } + }, + 0); + + } catch (RemoteException x) { + Log.e(TAG, "Exception caught: " + x); + return; + } + + final LowpanInterfaceTracker previous; + final LowpanInterfaceTracker agent; + + synchronized (mInterfaceMap) { + previous = mInterfaceMap.get(name); + + agent = new LowpanInterfaceTracker(lowpanInterface, mContext, getLooper()); + + mInterfaceMap.put(name, agent); + } + + if (previous != null) { + previous.unregister(); + onInterfaceRemoved(previous.mILowpanInterface, name); + } + + if (mStarted.get()) { + agent.register(); + } + + onInterfaceAdded(lowpanInterface, name); + } + + private void removeInterfaceByName(String name) { + final ILowpanInterface lowpanInterface; + + enforceManagePermission(); + + if (name == null) { + return; + } + + final LowpanInterfaceTracker agent; + + synchronized (mInterfaceMap) { + agent = mInterfaceMap.get(name); + + if (agent == null) { + return; + } + + lowpanInterface = agent.mILowpanInterface; + + if (mStarted.get()) { + agent.unregister(); + } + + mInterfaceMap.remove(name); + } + + onInterfaceRemoved(lowpanInterface, name); + } + + public void removeInterface(ILowpanInterface lowpanInterface) { + String name = null; + + try { + name = lowpanInterface.getName(); + } catch (RemoteException x) { + // Directly fetching the name failed, so fall back to + // a reverse lookup. + synchronized (mInterfaceMap) { + for (Map.Entry entry : mInterfaceMap.entrySet()) { + if (entry.getValue().mILowpanInterface == lowpanInterface) { + name = entry.getKey(); + break; + } + } + } + } + + removeInterfaceByName(name); + } + + public void addListener(ILowpanManagerListener listener) { + enforceAccessPermission(); + synchronized (mListenerSet) { + if (!mListenerSet.contains(listener)) { + try { + listener.asBinder() + .linkToDeath( + new IBinder.DeathRecipient() { + @Override + public void binderDied() { + synchronized (mListenerSet) { + mListenerSet.remove(listener); + } + } + }, + 0); + mListenerSet.add(listener); + } catch (RemoteException x) { + Log.e(TAG, "Exception caught: " + x); + } + } + } + } + + public void removeListener(ILowpanManagerListener listener) { + enforceAccessPermission(); + synchronized (mListenerSet) { + mListenerSet.remove(listener); + // TODO: Shouldn't we be unlinking from the death notification? + } + } +} -- cgit v1.2.3 From f15236e9c6adc5f69be5152bc61fe19bc975c222 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Mon, 15 May 2017 16:01:57 -0700 Subject: Initial commit of LoWPAN Command (lowpanctl) This is a command-line tool for managing LoWPAN networks. Bug: b/33073713 Change-Id: Id4a371bfe00c7de0ebb47f186eb1a286d81bad5a --- command/Android.mk | 36 ++ .../com/android/commands/lowpan/LowpanCtl.java | 445 +++++++++++++++++++++ command/lowpanctl | 6 + 3 files changed, 487 insertions(+) create mode 100644 command/Android.mk create mode 100644 command/java/com/android/commands/lowpan/LowpanCtl.java create mode 100755 command/lowpanctl diff --git a/command/Android.mk b/command/Android.mk new file mode 100644 index 0000000..82c0ffd --- /dev/null +++ b/command/Android.mk @@ -0,0 +1,36 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +ifneq (,$(findstring lowpan/java,$(FRAMEWORKS_BASE_SUBDIRS))) + +include $(CLEAR_VARS) +LOCAL_MODULE := lowpan-command +LOCAL_SRC_FILES += java/com/android/commands/lowpan/LowpanCtl.java +include $(BUILD_JAVA_LIBRARY) + +include $(CLEAR_VARS) +LOCAL_MODULE := lowpanctl +LOCAL_MODULE_TAGS := optional +LOCAL_REQUIRED_MODULES := lowpan-command +LOCAL_SRC_FILES := lowpanctl +LOCAL_MODULE_CLASS := EXECUTABLES +include $(BUILD_PREBUILT) + +endif + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/command/java/com/android/commands/lowpan/LowpanCtl.java b/command/java/com/android/commands/lowpan/LowpanCtl.java new file mode 100644 index 0000000..e23c094 --- /dev/null +++ b/command/java/com/android/commands/lowpan/LowpanCtl.java @@ -0,0 +1,445 @@ +/* + * Copyright 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 com.android.commands.lowpan; + +import android.net.lowpan.ILowpanInterface; +import android.net.lowpan.LowpanBeaconInfo; +import android.net.lowpan.LowpanCredential; +import android.net.lowpan.LowpanEnergyScanResult; +import android.net.lowpan.LowpanException; +import android.net.lowpan.LowpanIdentity; +import android.net.lowpan.LowpanInterface; +import android.net.lowpan.LowpanManager; +import android.net.lowpan.LowpanProvision; +import android.net.lowpan.LowpanScanner; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.util.AndroidRuntimeException; +import com.android.internal.os.BaseCommand; +import com.android.internal.util.HexDump; +import java.io.PrintStream; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; + +public class LowpanCtl extends BaseCommand { + private LowpanManager mLowpanManager; + private LowpanInterface mLowpanInterface; + private ILowpanInterface mILowpanInterface; + private String mLowpanInterfaceName; + + /** + * Command-line entry point. + * + * @param args The command-line arguments + */ + public static void main(String[] args) { + new LowpanCtl().run(args); + } + + @Override + public void onShowUsage(PrintStream out) { + out.println( + "usage: lowpanctl [options] [subcommand] [subcommand-options]\n" + + " lowpanctl status\n" + + " lowpanctl form\n" + + " lowpanctl join\n" + + " lowpanctl leave\n" + + " lowpanctl up\n" + + " lowpanctl down\n" + + " lowpanctl get [property-name]\n" + + " lowpanctl set [property-name]\n" + + " lowpanctl scan\n" + + " lowpanctl reset\n" + + " lowpanctl list\n" + + "\n"); + } + + private class CommandErrorException extends AndroidRuntimeException { + public CommandErrorException(String desc) { + super(desc); + } + } + + private void throwCommandError(String desc) { + throw new CommandErrorException(desc); + } + + private LowpanInterface getLowpanInterface() { + if (mLowpanInterface == null) { + if (mLowpanInterfaceName == null) { + String interfaceArray[] = mLowpanManager.getInterfaceList(); + if (interfaceArray.length != 0) { + mLowpanInterfaceName = interfaceArray[0]; + } else { + throwCommandError("No LoWPAN interfaces are present"); + } + } + mLowpanInterface = mLowpanManager.getInterface(mLowpanInterfaceName); + + if (mLowpanInterface == null) { + throwCommandError("Unknown LoWPAN interface \"" + mLowpanInterfaceName + "\""); + } + } + return mLowpanInterface; + } + + private ILowpanInterface getILowpanInterface() { + if (mILowpanInterface == null) { + mILowpanInterface = getLowpanInterface().getService(); + } + return mILowpanInterface; + } + + @Override + public void onRun() throws Exception { + mLowpanManager = LowpanManager.getManager(); + + if (mLowpanManager == null) { + System.err.println(NO_SYSTEM_ERROR_CODE); + throwCommandError("Can't connect to LoWPAN service; is the service running?"); + } + + try { + String op; + while ((op = nextArgRequired()) != null) { + if (op.equals("-I") || op.equals("--interface")) { + mLowpanInterfaceName = nextArgRequired(); + } else if (op.startsWith("-")) { + throwCommandError("Unrecognized argument \"" + op + "\""); + } else if (op.equals("status") || op.equals("stat")) { + runStatus(); + break; + } else if (op.equals("scan") || op.equals("netscan") || op.equals("ns")) { + runNetScan(); + break; + } else if (op.equals("attach") || op.equals("up")) { + runAttach(); + break; + } else if (op.equals("detach") || op.equals("down")) { + runDetach(); + break; + } else if (op.equals("join")) { + runJoin(); + break; + } else if (op.equals("form")) { + runForm(); + break; + } else if (op.equals("leave")) { + runLeave(); + break; + } else if (op.equals("get") || op.equals("getprop")) { + runGetProp(); + break; + } else if (op.equals("set") || op.equals("setprop")) { + runSetProp(); + break; + } else if (op.equals("energyscan") || op.equals("energy") || op.equals("es")) { + runEnergyScan(); + break; + } else if (op.equals("list") || op.equals("ls")) { + runListInterfaces(); + break; + } else if (op.equals("reset")) { + runReset(); + break; + } else { + showError("Error: unknown command '" + op + "'"); + break; + } + } + } catch (ServiceSpecificException x) { + System.out.println( + "ServiceSpecificException: " + x.errorCode + ": " + x.getLocalizedMessage()); + } catch (CommandErrorException x) { + System.out.println("error: " + x.getLocalizedMessage()); + } + } + + private void runReset() throws LowpanException { + getLowpanInterface().reset(); + } + + private LowpanProvision getProvisionFromArgs(boolean credentialRequired) { + LowpanProvision.Builder builder = new LowpanProvision.Builder(); + Map properties = new HashMap(); + LowpanIdentity.Builder identityBuilder = new LowpanIdentity.Builder(); + LowpanCredential credential = null; + String arg; + byte[] masterKey = null; + int masterKeyIndex = 0; + boolean hasName = false; + + while ((arg = nextArg()) != null) { + if (arg.equals("--name")) { + identityBuilder.setName(nextArgRequired()); + hasName = true; + } else if (arg.equals("-p") || arg.equals("--panid")) { + identityBuilder.setPanid(Integer.decode(nextArgRequired())); + } else if (arg.equals("-c") || arg.equals("--channel")) { + identityBuilder.setChannel(Integer.decode(nextArgRequired())); + } else if (arg.equals("-x") || arg.equals("--xpanid")) { + identityBuilder.setXpanid(HexDump.hexStringToByteArray(nextArgRequired())); + } else if (arg.equals("-k") || arg.equals("--master-key")) { + masterKey = HexDump.hexStringToByteArray(nextArgRequired()); + } else if (arg.equals("--master-key-index")) { + masterKeyIndex = Integer.decode(nextArgRequired()); + } else if (arg.startsWith("-") || hasName) { + throwCommandError("Unrecognized argument \"" + arg + "\""); + } else { + // This is the network name + identityBuilder.setName(arg); + hasName = true; + } + } + + if (credential == null && masterKey != null) { + if (masterKeyIndex == 0) { + credential = LowpanCredential.createMasterKey(masterKey); + } else { + credential = LowpanCredential.createMasterKey(masterKey, masterKeyIndex); + } + } + + if (credential != null) { + builder.setLowpanCredential(credential); + } else if (credentialRequired) { + throwCommandError("No credential (like a master key) was specified!"); + } + + return builder.setLowpanIdentity(identityBuilder.build()).build(); + } + + private void runAttach() throws LowpanException { + LowpanProvision provision = getProvisionFromArgs(true); + + System.out.println( + "Attaching to " + provision.getLowpanIdentity() + " with provided credential"); + + getLowpanInterface().attach(provision); + + System.out.println("Attached."); + } + + private void runDetach() throws LowpanException { + getLowpanInterface().setUp(false); + } + + private void runLeave() throws LowpanException { + getLowpanInterface().leave(); + } + + private void runJoin() throws LowpanException { + LowpanProvision provision = getProvisionFromArgs(true); + + System.out.println( + "Joining " + provision.getLowpanIdentity() + " with provided credential"); + + getLowpanInterface().join(provision); + + System.out.println("Joined."); + } + + private void runForm() throws LowpanException { + LowpanProvision provision = getProvisionFromArgs(false); + + if (provision.getLowpanCredential() != null) { + System.out.println( + "Forming " + + provision.getLowpanIdentity().toString() + + " with provided credential"); + } else { + System.out.println("Forming " + provision.getLowpanIdentity().toString()); + } + + getLowpanInterface().form(provision); + + System.out.println("Formed."); + } + + private String propAsString(String key, Object value) { + if (value instanceof byte[]) { + value = HexDump.toHexString((byte[]) value); + } else if (value instanceof String[]) { + if (((String[]) value).length == 0) { + value = "{ }"; + } else { + String renderedValue = "{\n"; + for (String row : (String[]) value) { + renderedValue += "\t\"" + row + "\"\n"; + } + value = renderedValue + "}"; + } + } else if (value instanceof int[]) { + if (((int[]) value).length == 0) { + value = "{ }"; + } else { + String renderedValue = "{\n"; + for (int row : (int[]) value) { + renderedValue += "\t" + Integer.toString(row) + "\n"; + } + value = renderedValue + "}"; + } + } else if ((value instanceof Long) && (key.equals(ILowpanInterface.KEY_NETWORK_XPANID))) { + value = "0x" + Long.toHexString((Long) value); + } else if ((value instanceof Integer) + && (key.equals(ILowpanInterface.KEY_NETWORK_PANID) + || key.equals("Thread:RLOC16"))) { + value = String.format("0x%04X", (Integer) value & 0xFFFF); + } + return value.toString(); + } + + private void runGetProp() throws LowpanException, RemoteException { + String key = nextArg(); + + if (key == null) { + try { + String key_list[] = getILowpanInterface().getPropertyKeys(); + + for (String subkey : key_list) { + Object value; + try { + value = getILowpanInterface().getPropertyAsString(subkey); + } catch (Exception x) { + value = x; + } + System.out.println(subkey + " => " + propAsString(subkey, value)); + } + } catch (RemoteException x) { + x.rethrowAsRuntimeException(); + } + } else { + Object value = getILowpanInterface().getPropertyAsString(key); + System.out.println(propAsString(key, value)); + } + } + + private void runSetProp() { + System.out.println("Command not implemented"); + } + + private void runStatus() throws LowpanException, RemoteException { + String statusKeys[] = { + ILowpanInterface.KEY_INTERFACE_ENABLED, + ILowpanInterface.KEY_INTERFACE_STATE, + "org.wpantund.Daemon:Version", + "org.wpantund.NCP:Version", + "org.wpantund.Config:NCP:DriverName", + "org.wpantund.IPv6:LinkLocalAddress", + "org.wpantund.IPv6:MeshLocalAddress", + }; + System.out.println( + "Current Network => " + getLowpanInterface().getLowpanIdentity().toString()); + + for (String key : statusKeys) { + Object value; + try { + value = getILowpanInterface().getPropertyAsString(key); + if (value != null) { + System.out.println(key + " => " + propAsString(key, value)); + } + } catch (ServiceSpecificException x) { + // Skip keys which cause remote exceptions. + } + } + } + + private void runListInterfaces() { + for (String name : mLowpanManager.getInterfaceList()) { + System.out.println(name); + } + } + + private void runNetScan() throws LowpanException, InterruptedException { + LowpanScanner scanner = getLowpanInterface().createScanner(); + String arg; + + while ((arg = nextArg()) != null) { + if (arg.equals("-c") || arg.equals("--channel")) { + scanner.addChannel(Integer.decode(nextArgRequired())); + } else { + throwCommandError("Unrecognized argument \"" + arg + "\""); + } + } + + Semaphore semaphore = new Semaphore(1); + + scanner.setCallback( + new LowpanScanner.Callback() { + @Override + public void onNetScanBeacon(LowpanBeaconInfo beacon) { + System.out.println(beacon.toString()); + } + + @Override + public void onScanFinished() { + semaphore.release(); + } + }); + + semaphore.acquire(); + scanner.startNetScan(); + + // Wait for our scan to complete. + if (semaphore.tryAcquire(1, 60L, TimeUnit.SECONDS)) { + semaphore.release(); + } else { + throwCommandError("Timeout while waiting for scan to complete."); + } + } + + private void runEnergyScan() throws LowpanException, InterruptedException { + LowpanScanner scanner = getLowpanInterface().createScanner(); + String arg; + + while ((arg = nextArg()) != null) { + if (arg.equals("-c") || arg.equals("--channel")) { + scanner.addChannel(Integer.decode(nextArgRequired())); + } else { + throwCommandError("Unrecognized argument \"" + arg + "\""); + } + } + + Semaphore semaphore = new Semaphore(1); + + scanner.setCallback( + new LowpanScanner.Callback() { + @Override + public void onEnergyScanResult(LowpanEnergyScanResult result) { + System.out.println(result.toString()); + } + + @Override + public void onScanFinished() { + semaphore.release(); + } + }); + + semaphore.acquire(); + scanner.startEnergyScan(); + + // Wait for our scan to complete. + if (semaphore.tryAcquire(1, 60L, TimeUnit.SECONDS)) { + semaphore.release(); + } else { + throwCommandError("Timeout while waiting for scan to complete."); + } + } +} diff --git a/command/lowpanctl b/command/lowpanctl new file mode 100755 index 0000000..188b9d6 --- /dev/null +++ b/command/lowpanctl @@ -0,0 +1,6 @@ +# Script to start "lowpan-command" on the device, which has a very rudimentary +# shell. +# +base=/system +export CLASSPATH=$base/framework/lowpan-command.jar +exec app_process $base/bin com.android.commands.lowpan.LowpanCtl "$@" -- cgit v1.2.3 From 4f8af68bdc56696791fc96aa64b738830aace9f9 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Wed, 5 Jul 2017 11:28:52 -0700 Subject: LowpanService: Updates to support IpManager. Bug: b/33073713 Change-Id: Ia630b321a1974442bf1e0b4e38558a21b2f93556 --- .../server/lowpan/LowpanInterfaceTracker.java | 158 ++++++++++----------- .../android/server/lowpan/LowpanServiceImpl.java | 3 +- 2 files changed, 74 insertions(+), 87 deletions(-) diff --git a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java index 32af169..afa3f80 100644 --- a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java +++ b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java @@ -19,33 +19,31 @@ package com.android.server.lowpan; import android.annotation.NonNull; import android.content.Context; import android.net.ConnectivityManager; +import android.net.IpPrefix; +import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.ip.IpManager; +import android.net.ip.IpManager.ProvisioningConfiguration; import android.net.lowpan.ILowpanInterface; import android.net.lowpan.LowpanException; import android.net.lowpan.LowpanInterface; import android.net.lowpan.LowpanProperties; -import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; -import android.os.RemoteException; -import android.os.ServiceManager; import android.util.Log; import com.android.internal.util.HexDump; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.net.NetlinkTracker; /** Tracks connectivity of a LoWPAN interface. */ class LowpanInterfaceTracker extends StateMachine { - //////////////////////////////////////////////////////////////////////////// // Misc Constants /** Network type string for NetworkInfo */ @@ -67,7 +65,6 @@ class LowpanInterfaceTracker extends StateMachine { /** Number of state machine log records. */ public static final short NUM_LOG_RECS_NORMAL = 100; - //////////////////////////////////////////////////////////////////////////// // Message Code Enumeration Constants /** The base for LoWPAN message codes */ @@ -80,18 +77,18 @@ class LowpanInterfaceTracker extends StateMachine { static final int CMD_STATE_CHANGE = BASE + 5; static final int CMD_LINK_PROPERTIES_CHANGE = BASE + 6; static final int CMD_UNWANTED = BASE + 7; + static final int CMD_PROVISIONING_SUCCESS = BASE + 8; + static final int CMD_PROVISIONING_FAILURE = BASE + 9; - //////////////////////////////////////////////////////////////////////////// // Services and interfaces ILowpanInterface mILowpanInterface; private LowpanInterface mLowpanInterface; private NetworkAgent mNetworkAgent; private NetworkFactory mNetworkFactory; - private INetworkManagementService mNmService; - private final NetlinkTracker mNetlinkTracker; + private final IpManager mIpManager; + private final IpManager.Callback mIpManagerCallback = new IpManagerCallback(); - //////////////////////////////////////////////////////////////////////////// // Instance Variables private String mInterfaceName; @@ -102,7 +99,6 @@ class LowpanInterfaceTracker extends StateMachine { private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities(); private String mState = ""; - //////////////////////////////////////////////////////////////////////////// // State machine state instances final DefaultState mDefaultState = new DefaultState(); @@ -112,14 +108,13 @@ class LowpanInterfaceTracker extends StateMachine { final CommissioningState mCommissioningState = new CommissioningState(); final AttachingState mAttachingState = new AttachingState(); final AttachedState mAttachedState = new AttachedState(); + final ObtainingIpState mObtainingIpState = new ObtainingIpState(); final FaultState mFaultState = new FaultState(); final ConnectedState mConnectedState = new ConnectedState(); - //////////////////////////////////////////////////////////////////////////// private LocalLowpanCallback mLocalLowpanCallback = new LocalLowpanCallback(); - //////////////////////////////////////////////////////////////////////////// // Misc Private Classes private class LocalLowpanCallback extends LowpanInterface.Callback { @@ -138,7 +133,23 @@ class LowpanInterfaceTracker extends StateMachine { } } - //////////////////////////////////////////////////////////////////////////// + class IpManagerCallback extends IpManager.Callback { + @Override + public void onProvisioningSuccess(LinkProperties newLp) { + LowpanInterfaceTracker.this.sendMessage(CMD_PROVISIONING_SUCCESS, newLp); + } + + @Override + public void onProvisioningFailure(LinkProperties newLp) { + LowpanInterfaceTracker.this.sendMessage(CMD_PROVISIONING_FAILURE, newLp); + } + + @Override + public void onLinkPropertiesChange(LinkProperties newLp) { + LowpanInterfaceTracker.this.sendMessage(CMD_LINK_PROPERTIES_CHANGE, newLp); + } + } + // State Definitions class InitState extends State { @@ -175,18 +186,6 @@ class LowpanInterfaceTracker extends StateMachine { mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_NONE, 0, NETWORK_TYPE, ""); mNetworkInfo.setIsAvailable(true); - if (mNmService == null) { - IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - mNmService = INetworkManagementService.Stub.asInterface(b); - } - - // Start tracking interface change events. - try { - mNmService.registerObserver(mNetlinkTracker); - } catch (RemoteException e) { - Log.e(TAG, "Could not register InterfaceObserver " + e); - } - mLowpanInterface.registerCallback(mLocalLowpanCallback); mState = ""; @@ -239,7 +238,7 @@ class LowpanInterfaceTracker extends StateMachine { transitionTo(mAttachingState); break; case LowpanInterface.STATE_ATTACHED: - transitionTo(mConnectedState); + transitionTo(mObtainingIpState); break; case LowpanInterface.STATE_FAULT: transitionTo(mFaultState); @@ -255,12 +254,6 @@ class LowpanInterfaceTracker extends StateMachine { @Override public void exit() { - try { - mNmService.unregisterObserver(mNetlinkTracker); - } catch (RemoteException x) { - Log.e(TAG, x.toString()); - } - mLowpanInterface.unregisterCallback(mLocalLowpanCallback); } } @@ -285,14 +278,6 @@ class LowpanInterfaceTracker extends StateMachine { } } - try { - mNmService.enableIpv6(mInterfaceName); - } catch (RemoteException x) { - Log.e( - TAG, - "Failed trying to enable IPv6 on " + mInterfaceName + ": " + x.toString()); - } - mNetworkFactory.register(); } @@ -304,16 +289,14 @@ class LowpanInterfaceTracker extends StateMachine { if (DBG) { Log.i(TAG, "UNWANTED."); } + // TODO: Figure out how to properly handle this. - try { - mLowpanInterface.leave(); - } catch (LowpanException x) { - Log.e(TAG, x.toString()); - } + shutdownNetworkAgent(); } break; + case CMD_PROVISIONING_SUCCESS: case CMD_LINK_PROPERTIES_CHANGE: mLinkProperties = (LinkProperties) message.obj; if (DBG) { @@ -323,6 +306,10 @@ class LowpanInterfaceTracker extends StateMachine { mNetworkAgent.sendLinkProperties(mLinkProperties); } break; + + case CMD_PROVISIONING_FAILURE: + Log.i(TAG, "Provisioning Failure: " + message.obj.toString()); + break; } return NOT_HANDLED; @@ -367,14 +354,6 @@ class LowpanInterfaceTracker extends StateMachine { class AttachingState extends State { @Override public void enter() { - try { - mNmService.enableIpv6(mInterfaceName); - } catch (RemoteException x) { - Log.e( - TAG, - "Failed trying to enable IPv6 on " + mInterfaceName + ": " + x.toString()); - } - mNetworkInfo.setDetailedState(DetailedState.CONNECTING, null, mHwAddr); mNetworkInfo.setIsAvailable(true); bringUpNetworkAgent(); @@ -393,6 +372,7 @@ class LowpanInterfaceTracker extends StateMachine { class AttachedState extends State { @Override public void enter() { + bringUpNetworkAgent(); mNetworkInfo.setIsAvailable(true); } @@ -419,18 +399,44 @@ class LowpanInterfaceTracker extends StateMachine { } } - class ConnectedState extends State { + class ObtainingIpState extends State { @Override public void enter() { - mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); - synchronized (mNetlinkTracker) { - mLinkProperties = mNetlinkTracker.getLinkProperties(); + + final ProvisioningConfiguration provisioningConfiguration = + mIpManager + .buildProvisioningConfiguration() + .withProvisioningTimeoutMs(0) + .withoutIpReachabilityMonitor() + .withoutIPv4() + .build(); + + mIpManager.startProvisioning(provisioningConfiguration); + } + + @Override + public boolean processMessage(Message message) { + + switch (message.what) { + case CMD_PROVISIONING_SUCCESS: + Log.i(TAG, "Provisioning Success: " + message.obj.toString()); + transitionTo(mConnectedState); + break; } + return NOT_HANDLED; + } - bringUpNetworkAgent(); + @Override + public void exit() {} + } - mNetworkAgent.sendLinkProperties(mLinkProperties); + class ConnectedState extends State { + @Override + public void enter() { + mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr); mNetworkAgent.sendNetworkInfo(mNetworkInfo); mNetworkAgent.sendNetworkScore(NETWORK_SCORE); } @@ -461,10 +467,7 @@ class LowpanInterfaceTracker extends StateMachine { public void exit() {} } - //////////////////////////////////////////////////////////////////////////// - - public LowpanInterfaceTracker( - ILowpanInterface lowpanInterface, Context context, Looper looper) { + public LowpanInterfaceTracker(Context context, ILowpanInterface ifaceService, Looper looper) { super(TAG, looper); if (DBG) { @@ -475,8 +478,8 @@ class LowpanInterfaceTracker extends StateMachine { setLogRecSize(NUM_LOG_RECS_NORMAL); setLogOnlyTransitions(false); - mILowpanInterface = lowpanInterface; - mLowpanInterface = LowpanInterface.from(mILowpanInterface); + mILowpanInterface = ifaceService; + mLowpanInterface = new LowpanInterface(context, ifaceService, looper); mContext = context; mInterfaceName = mLowpanInterface.getName(); @@ -484,10 +487,6 @@ class LowpanInterfaceTracker extends StateMachine { mLinkProperties = new LinkProperties(); mLinkProperties.setInterfaceName(mInterfaceName); - mNmService = - INetworkManagementService.Stub.asInterface( - ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); - // Initialize capabilities mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_LOWPAN); mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); @@ -495,7 +494,7 @@ class LowpanInterfaceTracker extends StateMachine { mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100); // Things don't seem to work properly without this. TODO: Investigate. - mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + //mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); // CHECKSTYLE:OFF IndentationCheck addState(mInitState); @@ -506,6 +505,7 @@ class LowpanInterfaceTracker extends StateMachine { addState(mCommissioningState, mNormalState); addState(mAttachingState, mNormalState); addState(mAttachedState, mNormalState); + addState(mObtainingIpState, mAttachedState); addState(mConnectedState, mAttachedState); // CHECKSTYLE:ON IndentationCheck @@ -524,19 +524,7 @@ class LowpanInterfaceTracker extends StateMachine { } }; - mNetlinkTracker = - new NetlinkTracker( - mInterfaceName, - new NetlinkTracker.Callback() { - @Override - public void update() { - synchronized (mNetlinkTracker) { - sendMessage( - CMD_LINK_PROPERTIES_CHANGE, - mNetlinkTracker.getLinkProperties()); - } - } - }); + mIpManager = new IpManager(mContext, mInterfaceName, mIpManagerCallback); start(); diff --git a/service/java/com/android/server/lowpan/LowpanServiceImpl.java b/service/java/com/android/server/lowpan/LowpanServiceImpl.java index be3eef6..08c4306 100644 --- a/service/java/com/android/server/lowpan/LowpanServiceImpl.java +++ b/service/java/com/android/server/lowpan/LowpanServiceImpl.java @@ -32,7 +32,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; - /** * LowpanService handles remote LoWPAN operation requests by implementing the ILowpanManager * interface. @@ -173,7 +172,7 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { synchronized (mInterfaceMap) { previous = mInterfaceMap.get(name); - agent = new LowpanInterfaceTracker(lowpanInterface, mContext, getLooper()); + agent = new LowpanInterfaceTracker(mContext, lowpanInterface, getLooper()); mInterfaceMap.put(name, agent); } -- cgit v1.2.3 From 47b51aa3f9cbc57ae18fef3402b06160a6f145a0 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Fri, 7 Jul 2017 12:57:15 -0700 Subject: Added .gitignore Change-Id: I33b56ae5a9b67ace9380c0d1e9864f0b67eb0ea2 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c6ef218 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea + -- cgit v1.2.3 From 49de520a96e39d96e2fdc041b2feaddaab8ee1d5 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Fri, 7 Jul 2017 12:59:05 -0700 Subject: Added simple testing scripts Change-Id: I8859d5b88550db9b5da8d9dc3a297cf1d556e365 --- tests/commandtest.sh | 45 +++++++++++++++++++++++++++++++++++++++++++++ tests/prepdevice.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100755 tests/commandtest.sh create mode 100755 tests/prepdevice.sh diff --git a/tests/commandtest.sh b/tests/commandtest.sh new file mode 100755 index 0000000..fb0fa0e --- /dev/null +++ b/tests/commandtest.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash + +cd "`dirname $0`" + +die () { + set +x # Turn off printing commands + echo "" + echo " *** fatal error: $*" + exit 1 +} + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +./prepdevice.sh || die "Unable to prepare device" + +sleep 2 + +echo "Running tests. . ." + +set -x # print commands + +adb shell killall wpantund 2> /dev/null + +adb shell wpantund -s 'system:ot-ncp\ 1' -o Config:Daemon:ExternalNetifManagement 1 & +WPANTUND_PID=$! +trap "kill -HUP $WPANTUND_PID 2> /dev/null" EXIT INT TERM + +sleep 2 + +kill -0 $WPANTUND_PID || die "wpantund failed to start" + +sleep 2 + +adb shell lowpanctl status || die +adb shell lowpanctl form blahnet || die +adb shell lowpanctl status || die +adb shell ifconfig wpan0 || die + +set +x # Turn off printing commands + +echo Finished. + diff --git a/tests/prepdevice.sh b/tests/prepdevice.sh new file mode 100755 index 0000000..027d64d --- /dev/null +++ b/tests/prepdevice.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +die () { + set +x # Turn off printing commands + echo "error: $*" + exit 1 +} + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +echo "Preparing device for LowpanService tests..." + +make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk \ + MODULES-IN-frameworks-opt-net-lowpan-service \ + MODULES-IN-frameworks-opt-net-lowpan-command \ + MODULES-IN-external-wpantund \ + MODULES-IN-external-openthread \ + || die "Build failed" + +set -x # print commands + +cp ${ANDROID_BUILD_TOP}/frameworks/native/data/etc/android.hardware.lowpan.xml ${ANDROID_PRODUCT_OUT}/system/etc/permissions/android.hardware.lowpan.xml + +adb root || die +adb wait-for-device || die +adb remount || die +adb shell stop || die +adb disable-verity +adb sync || die +adb shell start || die + +sleep 2 + +echo Device is ready. + -- cgit v1.2.3 From 41641f3e0d7ebccbb18ef1e03898688b50ae3e30 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Wed, 12 Jul 2017 17:07:53 -0700 Subject: lowpanctl: Stop using properties. This commit updates the `lowpanctl` tool to no longer use properties for fetching information about the interface, since this is no longer possible. Bug: b/63708348 Test: Compiled and tested manually by forming and scanning Change-Id: I8147b9e35780cf2114952cd59c384e5e3cead1aa --- .../com/android/commands/lowpan/LowpanCtl.java | 180 ++++++++++----------- 1 file changed, 84 insertions(+), 96 deletions(-) diff --git a/command/java/com/android/commands/lowpan/LowpanCtl.java b/command/java/com/android/commands/lowpan/LowpanCtl.java index e23c094..8e36841 100644 --- a/command/java/com/android/commands/lowpan/LowpanCtl.java +++ b/command/java/com/android/commands/lowpan/LowpanCtl.java @@ -26,7 +26,7 @@ import android.net.lowpan.LowpanInterface; import android.net.lowpan.LowpanManager; import android.net.lowpan.LowpanProvision; import android.net.lowpan.LowpanScanner; -import android.os.IBinder; +import android.net.LinkAddress; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.util.AndroidRuntimeException; @@ -57,18 +57,35 @@ public class LowpanCtl extends BaseCommand { public void onShowUsage(PrintStream out) { out.println( "usage: lowpanctl [options] [subcommand] [subcommand-options]\n" + + "options:\n" + + " -I / --interface ..... Interface Name\n" + + "subcommands:\n" + " lowpanctl status\n" + " lowpanctl form\n" + " lowpanctl join\n" + + " lowpanctl attach\n" + " lowpanctl leave\n" - + " lowpanctl up\n" - + " lowpanctl down\n" - + " lowpanctl get [property-name]\n" - + " lowpanctl set [property-name]\n" + + " lowpanctl enable\n" + + " lowpanctl disable\n" + + " lowpanctl show-credential\n" + " lowpanctl scan\n" + " lowpanctl reset\n" + " lowpanctl list\n" + + "\n" + + "usage: lowpanctl [options] join/form/attach [network-name]\n" + + "subcommand-options:\n" + + " --name ............. Network Name\n" + + " -p / --panid .............. PANID\n" + + " -c / --channel .......... Channel Index\n" + + " -x / --xpanid ............ XPANID\n" + + " -k / --master-key .... Master Key\n" + + " --master-key-index .... Key Index\n" + + "\n" + + "usage: lowpanctl [options] show-credential\n" + + "subcommand-options:\n" + + " -r / --raw ........................ Print only key contents\n" + "\n"); + } private class CommandErrorException extends AndroidRuntimeException { @@ -129,11 +146,17 @@ public class LowpanCtl extends BaseCommand { } else if (op.equals("scan") || op.equals("netscan") || op.equals("ns")) { runNetScan(); break; - } else if (op.equals("attach") || op.equals("up")) { + } else if (op.equals("attach")) { runAttach(); break; - } else if (op.equals("detach") || op.equals("down")) { - runDetach(); + } else if (op.equals("enable")) { + runEnable(); + break; + } else if (op.equals("disable")) { + runDisable(); + break; + } else if (op.equals("show-credential")) { + runShowCredential(); break; } else if (op.equals("join")) { runJoin(); @@ -144,12 +167,6 @@ public class LowpanCtl extends BaseCommand { } else if (op.equals("leave")) { runLeave(); break; - } else if (op.equals("get") || op.equals("getprop")) { - runGetProp(); - break; - } else if (op.equals("set") || op.equals("setprop")) { - runSetProp(); - break; } else if (op.equals("energyscan") || op.equals("energy") || op.equals("es")) { runEnergyScan(); break; @@ -176,6 +193,14 @@ public class LowpanCtl extends BaseCommand { getLowpanInterface().reset(); } + private void runEnable() throws LowpanException { + getLowpanInterface().setEnabled(true); + } + + private void runDisable() throws LowpanException { + getLowpanInterface().setEnabled(false); + } + private LowpanProvision getProvisionFromArgs(boolean credentialRequired) { LowpanProvision.Builder builder = new LowpanProvision.Builder(); Map properties = new HashMap(); @@ -200,6 +225,8 @@ public class LowpanCtl extends BaseCommand { masterKey = HexDump.hexStringToByteArray(nextArgRequired()); } else if (arg.equals("--master-key-index")) { masterKeyIndex = Integer.decode(nextArgRequired()); + } else if (arg.equals("--help")) { + throwCommandError(""); } else if (arg.startsWith("-") || hasName) { throwCommandError("Unrecognized argument \"" + arg + "\""); } else { @@ -237,10 +264,6 @@ public class LowpanCtl extends BaseCommand { System.out.println("Attached."); } - private void runDetach() throws LowpanException { - getLowpanInterface().setUp(false); - } - private void runLeave() throws LowpanException { getLowpanInterface().leave(); } @@ -262,10 +285,10 @@ public class LowpanCtl extends BaseCommand { if (provision.getLowpanCredential() != null) { System.out.println( "Forming " - + provision.getLowpanIdentity().toString() + + provision.getLowpanIdentity() + " with provided credential"); } else { - System.out.println("Forming " + provision.getLowpanIdentity().toString()); + System.out.println("Forming " + provision.getLowpanIdentity()); } getLowpanInterface().form(provision); @@ -273,92 +296,57 @@ public class LowpanCtl extends BaseCommand { System.out.println("Formed."); } - private String propAsString(String key, Object value) { - if (value instanceof byte[]) { - value = HexDump.toHexString((byte[]) value); - } else if (value instanceof String[]) { - if (((String[]) value).length == 0) { - value = "{ }"; - } else { - String renderedValue = "{\n"; - for (String row : (String[]) value) { - renderedValue += "\t\"" + row + "\"\n"; - } - value = renderedValue + "}"; - } - } else if (value instanceof int[]) { - if (((int[]) value).length == 0) { - value = "{ }"; - } else { - String renderedValue = "{\n"; - for (int row : (int[]) value) { - renderedValue += "\t" + Integer.toString(row) + "\n"; - } - value = renderedValue + "}"; - } - } else if ((value instanceof Long) && (key.equals(ILowpanInterface.KEY_NETWORK_XPANID))) { - value = "0x" + Long.toHexString((Long) value); - } else if ((value instanceof Integer) - && (key.equals(ILowpanInterface.KEY_NETWORK_PANID) - || key.equals("Thread:RLOC16"))) { - value = String.format("0x%04X", (Integer) value & 0xFFFF); + private void runStatus() throws LowpanException, RemoteException { + LowpanInterface iface = getLowpanInterface(); + StringBuffer sb = new StringBuffer(); + + sb.append(iface.getName()) + .append("\t") + .append(iface.getState() + " (" + iface.getRole() + ")"); + + if (iface.isUp()) { + sb.append(" UP"); } - return value.toString(); - } - private void runGetProp() throws LowpanException, RemoteException { - String key = nextArg(); + if (iface.isConnected()) { + sb.append(" CONNECTED"); + } - if (key == null) { - try { - String key_list[] = getILowpanInterface().getPropertyKeys(); + if (iface.isCommissioned()) { + sb.append(" COMMISSIONED"); + } - for (String subkey : key_list) { - Object value; - try { - value = getILowpanInterface().getPropertyAsString(subkey); - } catch (Exception x) { - value = x; - } - System.out.println(subkey + " => " + propAsString(subkey, value)); - } - } catch (RemoteException x) { - x.rethrowAsRuntimeException(); - } - } else { - Object value = getILowpanInterface().getPropertyAsString(key); - System.out.println(propAsString(key, value)); + sb + .append("\n\t") + .append(getLowpanInterface().getLowpanIdentity()); + + for (LinkAddress addr : iface.getLinkAddresses()) { + sb.append("\n\t").append(addr); } - } - private void runSetProp() { - System.out.println("Command not implemented"); + sb.append("\n"); + System.out.println(sb.toString()); } - private void runStatus() throws LowpanException, RemoteException { - String statusKeys[] = { - ILowpanInterface.KEY_INTERFACE_ENABLED, - ILowpanInterface.KEY_INTERFACE_STATE, - "org.wpantund.Daemon:Version", - "org.wpantund.NCP:Version", - "org.wpantund.Config:NCP:DriverName", - "org.wpantund.IPv6:LinkLocalAddress", - "org.wpantund.IPv6:MeshLocalAddress", - }; - System.out.println( - "Current Network => " + getLowpanInterface().getLowpanIdentity().toString()); - - for (String key : statusKeys) { - Object value; - try { - value = getILowpanInterface().getPropertyAsString(key); - if (value != null) { - System.out.println(key + " => " + propAsString(key, value)); - } - } catch (ServiceSpecificException x) { - // Skip keys which cause remote exceptions. + private void runShowCredential() throws LowpanException, RemoteException { + LowpanInterface iface = getLowpanInterface(); + boolean raw = false; + String arg; + while ((arg = nextArg()) != null) { + if (arg.equals("--raw") || arg.equals("-r")) { + raw = true; + } else { + throwCommandError("Unrecognized argument \"" + arg + "\""); } } + + LowpanCredential credential = iface.getLowpanCredential(); + if (raw) { + System.out.println(HexDump.toHexString(credential.getMasterKey())); + } else { + System.out.println( + iface.getName() + "\t" + credential.toSensitiveString()); + } } private void runListInterfaces() { -- cgit v1.2.3 From 9fc6ffb261beafe4becb5972f2c38437e5c211dd Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Wed, 12 Jul 2017 17:11:15 -0700 Subject: LowpanService: Stop using properties. This commit updates the LoWPAN Service to no longer use properties for fetching information about the interface, since this is no longer possible. Bug: b/63708348 Test: Compiled and tested manually by forming and scanning Change-Id: I4ee70b8b2a2e8f43239e36ae5f0626a51818e3ab --- .../server/lowpan/LowpanInterfaceTracker.java | 19 ++++++++++--------- .../android/server/lowpan/LowpanServiceImpl.java | 22 ++++++++++++++++------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java index afa3f80..cdfab75 100644 --- a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java +++ b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java @@ -32,9 +32,11 @@ import android.net.ip.IpManager.ProvisioningConfiguration; import android.net.lowpan.ILowpanInterface; import android.net.lowpan.LowpanException; import android.net.lowpan.LowpanInterface; -import android.net.lowpan.LowpanProperties; +import android.net.lowpan.LowpanRuntimeException; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.util.HexDump; import com.android.internal.util.Protocol; @@ -112,7 +114,6 @@ class LowpanInterfaceTracker extends StateMachine { final FaultState mFaultState = new FaultState(); final ConnectedState mConnectedState = new ConnectedState(); - private LocalLowpanCallback mLocalLowpanCallback = new LocalLowpanCallback(); // Misc Private Classes @@ -268,9 +269,13 @@ class LowpanInterfaceTracker extends StateMachine { if (mHwAddr == null) { byte[] hwAddr = null; try { - hwAddr = mLowpanInterface.getProperty(LowpanProperties.KEY_MAC_ADDRESS); - } catch (LowpanException x) { + hwAddr = mLowpanInterface.getService().getMacAddress(); + + } catch (RemoteException | ServiceSpecificException x) { + // Don't let misbehavior of an interface service + // crash the system service. Log.e(TAG, x.toString()); + transitionTo(mFaultState); } if (hwAddr != null) { @@ -296,7 +301,6 @@ class LowpanInterfaceTracker extends StateMachine { } break; - case CMD_PROVISIONING_SUCCESS: case CMD_LINK_PROPERTIES_CHANGE: mLinkProperties = (LinkProperties) message.obj; if (DBG) { @@ -424,7 +428,7 @@ class LowpanInterfaceTracker extends StateMachine { case CMD_PROVISIONING_SUCCESS: Log.i(TAG, "Provisioning Success: " + message.obj.toString()); transitionTo(mConnectedState); - break; + return HANDLED; } return NOT_HANDLED; } @@ -493,9 +497,6 @@ class LowpanInterfaceTracker extends StateMachine { mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100); mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100); - // Things don't seem to work properly without this. TODO: Investigate. - //mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - // CHECKSTYLE:OFF IndentationCheck addState(mInitState); addState(mDefaultState); diff --git a/service/java/com/android/server/lowpan/LowpanServiceImpl.java b/service/java/com/android/server/lowpan/LowpanServiceImpl.java index 08c4306..07677e3 100644 --- a/service/java/com/android/server/lowpan/LowpanServiceImpl.java +++ b/service/java/com/android/server/lowpan/LowpanServiceImpl.java @@ -25,6 +25,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.util.Log; import java.util.HashMap; import java.util.HashSet; @@ -111,9 +112,12 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { for (ILowpanManagerListener listener : mListenerSet) { try { listener.onInterfaceRemoved(lowpanInterface); - } catch (RemoteException x) { - // Just skip. + } catch (RemoteException | ServiceSpecificException x) { + // Don't let misbehavior of a listener + // crash the system service. Log.e(TAG, "Exception caught: " + x); + + // TODO: Consider removing the listener...? } } } @@ -125,9 +129,12 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { for (ILowpanManagerListener listener : mListenerSet) { try { listener.onInterfaceAdded(lowpanInterface); - } catch (RemoteException x) { - // Just skip. + } catch (RemoteException | ServiceSpecificException x) { + // Don't let misbehavior of a listener + // crash the system service. Log.e(TAG, "Exception caught: " + x); + + // TODO: Consider removing the listener...? } } } @@ -161,7 +168,9 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { }, 0); - } catch (RemoteException x) { + } catch (RemoteException | ServiceSpecificException x) { + // Don't let misbehavior of an interface + // crash the system service. Log.e(TAG, "Exception caught: " + x); return; } @@ -224,7 +233,7 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { try { name = lowpanInterface.getName(); - } catch (RemoteException x) { + } catch (RemoteException | ServiceSpecificException x) { // Directly fetching the name failed, so fall back to // a reverse lookup. synchronized (mInterfaceMap) { @@ -258,6 +267,7 @@ public class LowpanServiceImpl extends ILowpanManager.Stub { 0); mListenerSet.add(listener); } catch (RemoteException x) { + // We only get this exception if listener has already died. Log.e(TAG, "Exception caught: " + x); } } -- cgit v1.2.3 From 902d8a9f8531b8819d732572d2538e74daaf63ba Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Thu, 6 Jul 2017 11:39:20 -0700 Subject: LowpanInterfaceTracker: Add support for IpManager.InitialConfiguration Note that this commit depends on the following change-id: I2c20ddee41d9a22b9c5f19a643072ffe99d6ed3f Bug: b/62988545 b/33073713 Test: Compiled and manually tested for any obvious regressions Change-Id: I08b55261b0444f0b023bd8f8fea4dcc378fbc529 --- .../server/lowpan/LowpanInterfaceTracker.java | 77 +++++++++++++++++++--- 1 file changed, 67 insertions(+), 10 deletions(-) diff --git a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java index cdfab75..89b058c 100644 --- a/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java +++ b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java @@ -28,6 +28,7 @@ import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.ip.IpManager; +import android.net.ip.IpManager.InitialConfiguration; import android.net.ip.IpManager.ProvisioningConfiguration; import android.net.lowpan.ILowpanInterface; import android.net.lowpan.LowpanException; @@ -406,19 +407,75 @@ class LowpanInterfaceTracker extends StateMachine { class ObtainingIpState extends State { @Override public void enter() { - mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); - mNetworkAgent.sendNetworkInfo(mNetworkInfo); + InitialConfiguration initialConfiguration = new InitialConfiguration(); + + try { + for (LinkAddress address : mLowpanInterface.getLinkAddresses()) { + if (DBG) { + Log.i(TAG, "Adding link address: " + address); + } + initialConfiguration.ipAddresses.add(address); - final ProvisioningConfiguration provisioningConfiguration = - mIpManager - .buildProvisioningConfiguration() - .withProvisioningTimeoutMs(0) - .withoutIpReachabilityMonitor() - .withoutIPv4() - .build(); + IpPrefix prefix = new IpPrefix(address.getAddress(), address.getPrefixLength()); - mIpManager.startProvisioning(provisioningConfiguration); + initialConfiguration.directlyConnectedRoutes.add(prefix); + } + + for (IpPrefix prefix : mLowpanInterface.getLinkNetworks()) { + if (DBG) { + Log.i(TAG, "Adding directly connected route: " + prefix); + } + + initialConfiguration.directlyConnectedRoutes.add(prefix); + } + + } catch (LowpanException | LowpanRuntimeException x) { + Log.e(TAG, "Exception while populating InitialConfiguration: " + x); + transitionTo(mFaultState); + return; + + } catch (RuntimeException x) { + if (x.getCause() instanceof RemoteException) { + // Don't let misbehavior of an interface service + // crash the system service. + Log.e(TAG, x.toString()); + transitionTo(mFaultState); + + } else { + // This exception wasn't remote in origin, so we rethrow. + throw x; + } + } + + if (!initialConfiguration.isValid()) { + Log.e(TAG, "Invalid initial configuration: " + initialConfiguration); + transitionTo(mFaultState); + return; + } + + if (DBG) { + Log.d(TAG, "Using Initial configuration: " + initialConfiguration); + } + + final ProvisioningConfiguration.Builder builder = + mIpManager.buildProvisioningConfiguration(); + + builder.withInitialConfiguration(initialConfiguration).withProvisioningTimeoutMs(0); + + // LoWPAN networks generally don't have internet connectivity, + // so the reachability monitor would almost always fail. + builder.withoutIpReachabilityMonitor(); + + // We currently only support IPv6 on LoWPAN networks, although + // theoretically we could make this determination by examining + // the InitialConfiguration for any IPv4 addresses. + builder.withoutIPv4(); + + mIpManager.startProvisioning(builder.build()); + + mNetworkInfo.setDetailedState(DetailedState.OBTAINING_IPADDR, null, mHwAddr); + mNetworkAgent.sendNetworkInfo(mNetworkInfo); } @Override -- cgit v1.2.3 From d38415634a6e0d2175e888618a6ebc52dfcb861e Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Mon, 17 Jul 2017 19:32:56 -0700 Subject: lowpan: Introduce C++ versions of various java classes This change introduces C++ versions of the following java classes: * android.net.lowpan.LowpanIdentity * android.net.lowpan.LowpanCredential * android.net.lowpan.LowpanProvision * android.net.lowpan.LowpanBeaconInfo * android.net.lowpan.LowpanChannelInfo Bug: b/63707448 b/63708348 Test: Confirmed with unit tests from change id I41d590b1e77dc41873c4b9e9bf1b7f1bf859f74e Change-Id: I3dc7b9ca3b33b2ee5f92c8f76c28710997fb931d --- .gitattributes | 2 + libandroid_net_lowpan/Android.mk | 33 ++++ libandroid_net_lowpan/LowpanBeaconInfo.cpp | 218 +++++++++++++++++++++ libandroid_net_lowpan/LowpanChannelInfo.cpp | 114 +++++++++++ libandroid_net_lowpan/LowpanCredential.cpp | 149 ++++++++++++++ libandroid_net_lowpan/LowpanIdentity.cpp | 189 ++++++++++++++++++ libandroid_net_lowpan/LowpanProvision.cpp | 121 ++++++++++++ .../include/android/net/lowpan/LowpanBeaconInfo.h | 101 ++++++++++ .../include/android/net/lowpan/LowpanChannelInfo.h | 64 ++++++ .../include/android/net/lowpan/LowpanCredential.h | 72 +++++++ .../include/android/net/lowpan/LowpanIdentity.h | 90 +++++++++ .../include/android/net/lowpan/LowpanProvision.h | 69 +++++++ 12 files changed, 1222 insertions(+) create mode 100644 libandroid_net_lowpan/Android.mk create mode 100644 libandroid_net_lowpan/LowpanBeaconInfo.cpp create mode 100644 libandroid_net_lowpan/LowpanChannelInfo.cpp create mode 100644 libandroid_net_lowpan/LowpanCredential.cpp create mode 100644 libandroid_net_lowpan/LowpanIdentity.cpp create mode 100644 libandroid_net_lowpan/LowpanProvision.cpp create mode 100644 libandroid_net_lowpan/include/android/net/lowpan/LowpanBeaconInfo.h create mode 100644 libandroid_net_lowpan/include/android/net/lowpan/LowpanChannelInfo.h create mode 100644 libandroid_net_lowpan/include/android/net/lowpan/LowpanCredential.h create mode 100644 libandroid_net_lowpan/include/android/net/lowpan/LowpanIdentity.h create mode 100644 libandroid_net_lowpan/include/android/net/lowpan/LowpanProvision.h diff --git a/.gitattributes b/.gitattributes index f0600ce..bc24d41 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,5 @@ *.java text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof +*.cpp text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof +*.h text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof *.aidl text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof *.xml text whitespace=trailing-space,tab-in-indent,tabwidth=4,blank-at-eol,blank-at-eof diff --git a/libandroid_net_lowpan/Android.mk b/libandroid_net_lowpan/Android.mk new file mode 100644 index 0000000..730d97d --- /dev/null +++ b/libandroid_net_lowpan/Android.mk @@ -0,0 +1,33 @@ +# +# 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. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libandroid_net_lowpan +LOCAL_MODULE_TAGS := optional +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_SHARED_LIBRARIES += libbase +LOCAL_SHARED_LIBRARIES += libbinder +LOCAL_SHARED_LIBRARIES += libutils +LOCAL_SHARED_LIBRARIES += liblog +LOCAL_AIDL_INCLUDES += frameworks/native/aidl/binder +LOCAL_AIDL_INCLUDES += frameworks/base/lowpan/java +LOCAL_AIDL_INCLUDES += frameworks/base/core/java +LOCAL_SRC_FILES += $(call all-Iaidl-files-under, ../../../../base/lowpan/java/android/net/lowpan) +LOCAL_SRC_FILES += $(call all-cpp-files-under) +include $(BUILD_SHARED_LIBRARY) diff --git a/libandroid_net_lowpan/LowpanBeaconInfo.cpp b/libandroid_net_lowpan/LowpanBeaconInfo.cpp new file mode 100644 index 0000000..95746df --- /dev/null +++ b/libandroid_net_lowpan/LowpanBeaconInfo.cpp @@ -0,0 +1,218 @@ +/* + * 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. + */ + +#define LOG_TAG "LowpanBeaconInfo" + +#include + +#include +#include +#include + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::Parcel; +using android::status_t; +using android::UNEXPECTED_NULL; +using android::net::lowpan::LowpanBeaconInfo; +using namespace ::android::binder; + +namespace android { + +namespace net { + +namespace lowpan { + +#define RETURN_IF_FAILED(calledOnce) \ + { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } + +LowpanBeaconInfo::Builder::Builder() { +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setName(const std::string& value) { + mIdentityBuilder.setName(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setType(const std::string& value) { + mIdentityBuilder.setType(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setType(const ::android::String16& value) { + mIdentityBuilder.setType(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setXpanid(const std::vector& value) { + mIdentityBuilder.setXpanid(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setXpanid(const uint8_t* valuePtr, int32_t valueLen) { + mIdentityBuilder.setXpanid(valuePtr, valueLen); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setPanid(int32_t value) { + mIdentityBuilder.setPanid(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setChannel(int32_t value) { + mIdentityBuilder.setChannel(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setLowpanIdentity(const LowpanIdentity& value) { + mIdentityBuilder.setLowpanIdentity(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setRssi(int32_t value) { + mRssi = value; + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setLqi(int32_t value) { + mLqi = value; + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setBeaconAddress(const std::vector& value) { + mBeaconAddress = value; + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setBeaconAddress(const uint8_t* valuePtr, int32_t valueLen) { + mBeaconAddress.clear(); + mBeaconAddress.insert(mBeaconAddress.end(), valuePtr, valuePtr + valueLen); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::setFlag(int32_t value) { + mFlags.insert(value); + return *this; +} + +LowpanBeaconInfo::Builder& LowpanBeaconInfo::Builder::clearFlag(int32_t value) { + mFlags.erase(value); + return *this; +} + +LowpanBeaconInfo LowpanBeaconInfo::Builder::build(void) const { + return LowpanBeaconInfo(*this); +} + +LowpanBeaconInfo::LowpanBeaconInfo(const LowpanBeaconInfo::Builder& builder) : + mIdentity(builder.mIdentityBuilder.build()), + mRssi(builder.mRssi), + mLqi(builder.mLqi), + mBeaconAddress(builder.mBeaconAddress), + mFlags(builder.mFlags) +{ +} + +status_t LowpanBeaconInfo::writeToParcel(Parcel* parcel) const { + /* + * Keep implementation in sync with writeToParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanBeaconInfo.java. + */ + + RETURN_IF_FAILED(mIdentity.writeToParcel(parcel)); + RETURN_IF_FAILED(parcel->writeInt32(mRssi)); + RETURN_IF_FAILED(parcel->writeInt32(mLqi)); + RETURN_IF_FAILED(parcel->writeByteVector(mBeaconAddress)); + RETURN_IF_FAILED(parcel->writeInt32(mFlags.size())); + + std::set::const_iterator iter; + std::set::const_iterator end = mFlags.end(); + + for (iter = mFlags.begin(); iter != end; ++iter) { + RETURN_IF_FAILED(parcel->writeInt32(*iter)); + } + + return NO_ERROR; +} + +status_t LowpanBeaconInfo::readFromParcel(const Parcel* parcel) { + /* + * Keep implementation in sync with readFromParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanBeaconInfo.java. + */ + + RETURN_IF_FAILED(mIdentity.readFromParcel(parcel)); + RETURN_IF_FAILED(parcel->readInt32(&mRssi)); + RETURN_IF_FAILED(parcel->readInt32(&mLqi)); + RETURN_IF_FAILED(parcel->readByteVector(&mBeaconAddress)); + + int32_t flagCount = 0; + + RETURN_IF_FAILED(parcel->readInt32(&flagCount)); + + if (flagCount < 0) { + ALOGE("Bad flag count"); + return BAD_VALUE; + } + + mFlags.clear(); + + while (flagCount--) { + int32_t flag = 0; + RETURN_IF_FAILED(parcel->readInt32(&flag)); + mFlags.insert(flag); + } + + return NO_ERROR; +} + +bool LowpanBeaconInfo::operator==(const LowpanBeaconInfo& rhs) +{ + if (mIdentity != rhs.mIdentity) { + return false; + } + + if (mRssi != rhs.mRssi) { + return false; + } + + if (mLqi != rhs.mLqi) { + return false; + } + + if (mBeaconAddress != rhs.mBeaconAddress) { + return false; + } + + if (mFlags != rhs.mFlags) { + return false; + } + + return true; +} + +} // namespace lowpan + +} // namespace net + +} // namespace android diff --git a/libandroid_net_lowpan/LowpanChannelInfo.cpp b/libandroid_net_lowpan/LowpanChannelInfo.cpp new file mode 100644 index 0000000..af4e7a2 --- /dev/null +++ b/libandroid_net_lowpan/LowpanChannelInfo.cpp @@ -0,0 +1,114 @@ +/* + * 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. + */ + +#define LOG_TAG "LowpanChannelInfo" + +#include + +#include +#include +#include + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::Parcel; +using android::status_t; +using android::UNEXPECTED_NULL; +using android::net::lowpan::LowpanChannelInfo; +using namespace ::android::binder; + +namespace android { + +namespace net { + +namespace lowpan { + +#define RETURN_IF_FAILED(calledOnce) \ + { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } + +status_t LowpanChannelInfo::writeToParcel(Parcel* parcel) const { + /* + * Keep implementation in sync with writeToParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanChannelInfo.java. + */ + + RETURN_IF_FAILED(parcel->writeInt32(mIndex)); + RETURN_IF_FAILED(parcel->writeUtf8AsUtf16(mName)); + RETURN_IF_FAILED(parcel->writeFloat(mSpectrumCenterFrequency)); + RETURN_IF_FAILED(parcel->writeFloat(mSpectrumBandwidth)); + RETURN_IF_FAILED(parcel->writeInt32(mMaxTxPower)); + RETURN_IF_FAILED(parcel->writeBool(mIsMaskedByRegulatoryDomain)); + + return NO_ERROR; +} + +status_t LowpanChannelInfo::readFromParcel(const Parcel* parcel) { + /* + * Keep implementation in sync with readFromParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanChannelInfo.java. + */ + + RETURN_IF_FAILED(parcel->readInt32(&mIndex)); + RETURN_IF_FAILED(parcel->readUtf8FromUtf16(&mName)); + RETURN_IF_FAILED(parcel->readFloat(&mSpectrumCenterFrequency)); + RETURN_IF_FAILED(parcel->readFloat(&mSpectrumBandwidth)); + RETURN_IF_FAILED(parcel->readInt32(&mMaxTxPower)); + RETURN_IF_FAILED(parcel->readBool(&mIsMaskedByRegulatoryDomain)); + + return NO_ERROR; +} + +bool LowpanChannelInfo::operator==(const LowpanChannelInfo& rhs) +{ + if (mIndex != rhs.mIndex) { + return false; + } + + if (mName != rhs.mName) { + return false; + } + + if (mSpectrumCenterFrequency != rhs.mSpectrumCenterFrequency) { + return false; + } + + if (mSpectrumBandwidth != rhs.mSpectrumBandwidth) { + return false; + } + + if (mMaxTxPower != rhs.mMaxTxPower) { + return false; + } + + if (mIsMaskedByRegulatoryDomain != rhs.mIsMaskedByRegulatoryDomain) { + return false; + } + + return true; +} + +} // namespace lowpan + +} // namespace net + +} // namespace android diff --git a/libandroid_net_lowpan/LowpanCredential.cpp b/libandroid_net_lowpan/LowpanCredential.cpp new file mode 100644 index 0000000..f0c6109 --- /dev/null +++ b/libandroid_net_lowpan/LowpanCredential.cpp @@ -0,0 +1,149 @@ +/* + * 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. + */ + +#define LOG_TAG "LowpanCredential" + +#include + +#include +#include +#include + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::Parcel; +using android::status_t; +using android::UNEXPECTED_NULL; +using android::net::lowpan::LowpanCredential; +using namespace ::android::binder; + +namespace android { + +namespace net { + +namespace lowpan { + +#define RETURN_IF_FAILED(calledOnce) \ + { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } + +LowpanCredential::LowpanCredential() : mMasterKeyIndex(UNSPECIFIED_MASTER_KEY_INDEX) { } + +status_t LowpanCredential::initMasterKey(LowpanCredential& out, const uint8_t* masterKeyBytes, int masterKeyLen, int masterKeyIndex) +{ + if (masterKeyLen < 0) { + return BAD_INDEX; + } else if (masterKeyLen > MASTER_KEY_MAX_SIZE) { + return BAD_INDEX; + } else if (masterKeyBytes == NULL) { + return BAD_VALUE; + } + + out.mMasterKey.clear(); + out.mMasterKey.insert(out.mMasterKey.end(), masterKeyBytes, masterKeyBytes + masterKeyLen); + out.mMasterKeyIndex = masterKeyIndex; + + return NO_ERROR; +} + +status_t LowpanCredential::initMasterKey(LowpanCredential& out, const uint8_t* masterKeyBytes, int masterKeyLen) +{ + return LowpanCredential::initMasterKey(out, masterKeyBytes, masterKeyLen, 0); +} + +status_t LowpanCredential::initMasterKey(LowpanCredential& out, const std::vector& masterKey, int masterKeyIndex) +{ + return LowpanCredential::initMasterKey(out, &masterKey.front(), masterKey.size(), masterKeyIndex); +} + +status_t LowpanCredential::initMasterKey(LowpanCredential& out, const std::vector& masterKey) +{ + return LowpanCredential::initMasterKey(out, masterKey, 0); +} + +bool LowpanCredential::isMasterKey() const { + return mMasterKey.size() > 0; +} + +bool LowpanCredential::getMasterKey(std::vector* masterKey) const { + if (isMasterKey()) { + *masterKey = mMasterKey; + return true; + } + return false; +} + +bool LowpanCredential::getMasterKey(const uint8_t** masterKey, int* masterKeyLen) const { + if (isMasterKey()) { + if (masterKey) { + *masterKey = &mMasterKey.front(); + } + if (masterKeyLen) { + *masterKeyLen = mMasterKey.size(); + } + return true; + } + return false; +} + +int LowpanCredential::getMasterKeyIndex() const { + return mMasterKeyIndex; +} + +status_t LowpanCredential::writeToParcel(Parcel* parcel) const { + /* + * Keep implementation in sync with writeToParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanCredential.java. + */ + RETURN_IF_FAILED(parcel->writeByteVector(mMasterKey)); + RETURN_IF_FAILED(parcel->writeInt32(mMasterKeyIndex)); + return NO_ERROR; +} + +status_t LowpanCredential::readFromParcel(const Parcel* parcel) { + /* + * Keep implementation in sync with readFromParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanCredential.java. + */ + RETURN_IF_FAILED(parcel->readByteVector(&mMasterKey)); + RETURN_IF_FAILED(parcel->readInt32(&mMasterKeyIndex)); + return NO_ERROR; +} + +bool LowpanCredential::operator==(const LowpanCredential& rhs) +{ + if (mMasterKey != rhs.mMasterKey) { + return false; + } + + if (mMasterKeyIndex != rhs.mMasterKeyIndex) { + return false; + } + + return true; +} + +} // namespace lowpan + +} // namespace net + +} // namespace android diff --git a/libandroid_net_lowpan/LowpanIdentity.cpp b/libandroid_net_lowpan/LowpanIdentity.cpp new file mode 100644 index 0000000..0e64c20 --- /dev/null +++ b/libandroid_net_lowpan/LowpanIdentity.cpp @@ -0,0 +1,189 @@ +/* + * 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. + */ + +#define LOG_TAG "LowpanIdentity" + +#include + +#include +#include +#include + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::Parcel; +using android::status_t; +using android::UNEXPECTED_NULL; +using android::net::lowpan::LowpanIdentity; +using namespace ::android::binder; + +namespace android { + +namespace net { + +namespace lowpan { + +#define RETURN_IF_FAILED(calledOnce) \ + { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } + +bool LowpanIdentity::getName(std::string* value) const { + if (value != NULL) { + *value = mName; + } + return true; +} +bool LowpanIdentity::getType(std::string* value) const { + if (value != NULL) { + *value = mType; + } + return true; +} +bool LowpanIdentity::getXpanid(std::vector* value) const { + if (value != NULL) { + *value = mXpanid; + } + return true; +} +int32_t LowpanIdentity::getPanid(void) const { + return mPanid; +} +int32_t LowpanIdentity::getChannel(void) const { + return mChannel; +} + +LowpanIdentity::Builder::Builder() { +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setName(const std::string& value) { + mIdentity.mName = value; + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setType(const std::string& value) { + mIdentity.mType = value; + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setType(const ::android::String16& value) { + return setType(String8(value).string()); +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setXpanid(const std::vector& value) { + mIdentity.mXpanid = value; + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setXpanid(const uint8_t* valuePtr, int32_t valueLen) { + mIdentity.mXpanid.clear(); + mIdentity.mXpanid.insert(mIdentity.mXpanid.end(), valuePtr, valuePtr + valueLen); + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setPanid(int32_t value) { + mIdentity.mPanid = value; + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setChannel(int32_t value) { + mIdentity.mChannel = value; + return *this; +} + +LowpanIdentity::Builder& LowpanIdentity::Builder::setLowpanIdentity(const LowpanIdentity& value) { + mIdentity = value; + return *this; +} + +LowpanIdentity LowpanIdentity::Builder::build(void) const { + return mIdentity; +} + +LowpanIdentity::LowpanIdentity() : mPanid(UNSPECIFIED_PANID), mChannel(UNSPECIFIED_CHANNEL) { +} + +status_t LowpanIdentity::writeToParcel(Parcel* parcel) const { + /* + * Keep implementation in sync with writeToParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanIdentity.java. + */ + + std::vector rawName(mName.begin(), mName.end()); + + RETURN_IF_FAILED(parcel->writeByteVector(rawName)); + RETURN_IF_FAILED(parcel->writeUtf8AsUtf16(mType)); + RETURN_IF_FAILED(parcel->writeByteVector(mXpanid)); + RETURN_IF_FAILED(parcel->writeInt32(mPanid)); + RETURN_IF_FAILED(parcel->writeInt32(mChannel)); + return NO_ERROR; +} + +status_t LowpanIdentity::readFromParcel(const Parcel* parcel) { + /* + * Keep implementation in sync with readFromParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanIdentity.java. + */ + + std::vector rawName; + + RETURN_IF_FAILED(parcel->readByteVector(&rawName)); + + mName = std::string((const char*)&rawName.front(), rawName.size()); + + RETURN_IF_FAILED(parcel->readUtf8FromUtf16(&mType)); + RETURN_IF_FAILED(parcel->readByteVector(&mXpanid)); + RETURN_IF_FAILED(parcel->readInt32(&mPanid)); + RETURN_IF_FAILED(parcel->readInt32(&mChannel)); + return NO_ERROR; +} + +bool LowpanIdentity::operator==(const LowpanIdentity& rhs) +{ + const LowpanIdentity& lhs = *this; + + if (lhs.mName != rhs.mName) { + return false; + } + + if (lhs.mType != rhs.mType) { + return false; + } + + if (lhs.mXpanid != rhs.mXpanid) { + return false; + } + + if (lhs.mPanid != rhs.mPanid) { + return false; + } + + if (lhs.mChannel != rhs.mChannel) { + return false; + } + return true; +} + +} // namespace lowpan + +} // namespace net + +} // namespace android diff --git a/libandroid_net_lowpan/LowpanProvision.cpp b/libandroid_net_lowpan/LowpanProvision.cpp new file mode 100644 index 0000000..315ea54 --- /dev/null +++ b/libandroid_net_lowpan/LowpanProvision.cpp @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#define LOG_TAG "LowpanProvision" + +#include + +#include +#include +#include + +using android::BAD_TYPE; +using android::BAD_VALUE; +using android::NO_ERROR; +using android::Parcel; +using android::status_t; +using android::UNEXPECTED_NULL; +using android::net::lowpan::LowpanProvision; +using namespace ::android::binder; + +namespace android { + +namespace net { + +namespace lowpan { + +#define RETURN_IF_FAILED(calledOnce) \ + { \ + status_t returnStatus = calledOnce; \ + if (returnStatus) { \ + ALOGE("Failed at %s:%d (%s)", __FILE__, __LINE__, __func__); \ + return returnStatus; \ + } \ + } +LowpanProvision::LowpanProvision(const LowpanIdentity& identity, const LowpanCredential& credential) + : mIdentity(identity), mCredential(credential), mHasCredential(true) +{ +} + +LowpanProvision::LowpanProvision(const LowpanIdentity& identity) + : mIdentity(identity), mHasCredential(false) +{ +} + +const LowpanIdentity* LowpanProvision::getLowpanIdentity() const { + return &mIdentity; +} + +const LowpanCredential* LowpanProvision::getLowpanCredential() const { + return mHasCredential + ? &mCredential + : NULL; +} + +status_t LowpanProvision::writeToParcel(Parcel* parcel) const { + /* + * Keep implementation in sync with writeToParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanProvision.java. + */ + + RETURN_IF_FAILED(mIdentity.writeToParcel(parcel)); + RETURN_IF_FAILED(parcel->writeBool(mHasCredential)); + + if (mHasCredential) { + RETURN_IF_FAILED(mCredential.writeToParcel(parcel)); + } + + return NO_ERROR; +} + +status_t LowpanProvision::readFromParcel(const Parcel* parcel) { + /* + * Keep implementation in sync with readFromParcel() in + * frameworks/base/lowpan/java/android/net/android/net/lowpan/LowpanProvision.java. + */ + + RETURN_IF_FAILED(mIdentity.readFromParcel(parcel)); + RETURN_IF_FAILED(parcel->readBool(&mHasCredential)); + + if (mHasCredential) { + RETURN_IF_FAILED(mCredential.readFromParcel(parcel)); + } + + return NO_ERROR; +} + +bool LowpanProvision::operator==(const LowpanProvision& rhs) +{ + if (mIdentity != rhs.mIdentity) { + return false; + } + + if (mHasCredential != rhs.mHasCredential) { + return false; + } + + if (mHasCredential && mCredential != rhs.mCredential) { + return false; + } + + return true; +} + +} // namespace lowpan + +} // namespace net + +} // namespace android diff --git a/libandroid_net_lowpan/include/android/net/lowpan/LowpanBeaconInfo.h b/libandroid_net_lowpan/include/android/net/lowpan/LowpanBeaconInfo.h new file mode 100644 index 0000000..9a971ef --- /dev/null +++ b/libandroid_net_lowpan/include/android/net/lowpan/LowpanBeaconInfo.h @@ -0,0 +1,101 @@ +/* + * 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. + */ + +#ifndef ANDROID_LOWPAN_BEACON_INFO_H +#define ANDROID_LOWPAN_BEACON_INFO_H + +#include +#include +#include +#include + +#include "LowpanIdentity.h" + +namespace android { + +namespace net { + +namespace lowpan { + +/* + * C++ implementation of the Java class android.net.lowpan.LowpanBeaconInfo + */ +class LowpanBeaconInfo : public Parcelable { +public: + static const int32_t FLAG_CAN_ASSIST = 1; + + class Builder; + LowpanBeaconInfo() = default; + virtual ~LowpanBeaconInfo() = default; + LowpanBeaconInfo(const LowpanBeaconInfo& x) = default; + + bool operator==(const LowpanBeaconInfo& rhs); + bool operator!=(const LowpanBeaconInfo& rhs) { return !(*this == rhs); } + +public: + // Overrides + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + +private: + LowpanBeaconInfo(const Builder& builder); + +private: + // Data + LowpanIdentity mIdentity; + int32_t mRssi; + int32_t mLqi; + std::vector mBeaconAddress; + std::set mFlags; +}; + +class LowpanBeaconInfo::Builder { + friend class LowpanBeaconInfo; +public: + Builder(); + Builder& setName(const std::string& value); + Builder& setType(const std::string& value); + Builder& setType(const ::android::String16& value); + Builder& setXpanid(const std::vector& value); + Builder& setXpanid(const uint8_t* valuePtr, int32_t valueLen); + Builder& setPanid(int32_t value); + Builder& setChannel(int32_t value); + Builder& setLowpanIdentity(const LowpanIdentity& value); + + Builder& setRssi(int32_t value); + Builder& setLqi(int32_t value); + Builder& setBeaconAddress(const std::vector& value); + Builder& setBeaconAddress(const uint8_t* valuePtr, int32_t valueLen); + Builder& setFlag(int32_t value); + Builder& clearFlag(int32_t value); + + LowpanBeaconInfo build(void) const; +private: + LowpanIdentity::Builder mIdentityBuilder; + + int32_t mRssi; + int32_t mLqi; + std::vector mBeaconAddress; + std::set mFlags; +}; + +} // namespace lowpan + +} // namespace net + +} // namespace android + +#endif // ANDROID_LOWPAN_BEACON_INFO_H diff --git a/libandroid_net_lowpan/include/android/net/lowpan/LowpanChannelInfo.h b/libandroid_net_lowpan/include/android/net/lowpan/LowpanChannelInfo.h new file mode 100644 index 0000000..e29820a --- /dev/null +++ b/libandroid_net_lowpan/include/android/net/lowpan/LowpanChannelInfo.h @@ -0,0 +1,64 @@ +/* + * 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. + */ + +#ifndef ANDROID_LOWPAN_CHANNEL_INFO_H +#define ANDROID_LOWPAN_CHANNEL_INFO_H + +#include +#include +#include +#include + +namespace android { + +namespace net { + +namespace lowpan { + +/* + * C++ implementation of the Java class android.net.lowpan.LowpanChannelInfo + */ +class LowpanChannelInfo : public Parcelable { +public: + LowpanChannelInfo() = default; + virtual ~LowpanChannelInfo() = default; + LowpanChannelInfo(const LowpanChannelInfo& x) = default; + + bool operator==(const LowpanChannelInfo& rhs); + bool operator!=(const LowpanChannelInfo& rhs) { return !(*this == rhs); } + +public: + // Overrides + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + +private: + // Data + int32_t mIndex; + std::string mName; + float mSpectrumCenterFrequency; + float mSpectrumBandwidth; + int32_t mMaxTxPower; + bool mIsMaskedByRegulatoryDomain; +}; + +} // namespace lowpan + +} // namespace net + +} // namespace android + +#endif // ANDROID_LOWPAN_CHANNEL_INFO_H diff --git a/libandroid_net_lowpan/include/android/net/lowpan/LowpanCredential.h b/libandroid_net_lowpan/include/android/net/lowpan/LowpanCredential.h new file mode 100644 index 0000000..c8ac90b --- /dev/null +++ b/libandroid_net_lowpan/include/android/net/lowpan/LowpanCredential.h @@ -0,0 +1,72 @@ +/* + * 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. + */ + +#ifndef ANDROID_LOWPAN_CREDENTIAL_H +#define ANDROID_LOWPAN_CREDENTIAL_H + +#include +#include +#include + +namespace android { + +namespace net { + +namespace lowpan { + +/* + * C++ implementation of the Java class android.net.lowpan.LowpanCredential + */ +class LowpanCredential : public Parcelable { +public: + static const int32_t UNSPECIFIED_MASTER_KEY_INDEX = 0; + static const int MASTER_KEY_MAX_SIZE = 1048576; + + LowpanCredential(); + virtual ~LowpanCredential() = default; + LowpanCredential(const LowpanCredential& x) = default; + + static status_t initMasterKey(LowpanCredential& out, const std::vector& masterKey, int32_t masterKeyIndex); + static status_t initMasterKey(LowpanCredential& out, const std::vector& masterKey); + static status_t initMasterKey(LowpanCredential& out, const uint8_t* masterKeyBytes, int masterKeyLen, int32_t masterKeyIndex); + static status_t initMasterKey(LowpanCredential& out, const uint8_t* masterKeyBytes, int masterKeyLen); + + bool isMasterKey()const; + bool getMasterKey(std::vector* masterKey)const; + bool getMasterKey(const uint8_t** masterKey, int* masterKeyLen)const; + int32_t getMasterKeyIndex()const; + + bool operator==(const LowpanCredential& rhs); + bool operator!=(const LowpanCredential& rhs) { return !(*this == rhs); } + +public: + // Overrides + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + +private: + // Data + std::vector mMasterKey; + int32_t mMasterKeyIndex; +}; + +} // namespace lowpan + +} // namespace net + +} // namespace android + +#endif // ANDROID_LOWPAN_CREDENTIAL_H diff --git a/libandroid_net_lowpan/include/android/net/lowpan/LowpanIdentity.h b/libandroid_net_lowpan/include/android/net/lowpan/LowpanIdentity.h new file mode 100644 index 0000000..c82446a --- /dev/null +++ b/libandroid_net_lowpan/include/android/net/lowpan/LowpanIdentity.h @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#ifndef ANDROID_LOWPAN_IDENTITY_H +#define ANDROID_LOWPAN_IDENTITY_H + +#include +#include +#include +#include + +namespace android { + +namespace net { + +namespace lowpan { + +/* + * C++ implementation of the Java class android.net.lowpan.LowpanIdentity + */ +class LowpanIdentity : public Parcelable { +public: + class Builder; + static const int32_t UNSPECIFIED_PANID = 0xFFFFFFFF; + static const int32_t UNSPECIFIED_CHANNEL = -1; + + LowpanIdentity(); + virtual ~LowpanIdentity() = default; + LowpanIdentity(const LowpanIdentity& x) = default; + + bool operator==(const LowpanIdentity& rhs); + bool operator!=(const LowpanIdentity& rhs) { return !(*this == rhs); } + + bool getName(std::string* value) const; + bool getType(std::string* value) const; + bool getXpanid(std::vector* value) const; + int32_t getPanid(void) const; + int32_t getChannel(void) const; + +public: + // Overrides + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + +private: + // Data + std::string mName; + std::string mType; + std::vector mXpanid; + int32_t mPanid; + int32_t mChannel; +}; + +class LowpanIdentity::Builder { +public: + Builder(); + Builder& setName(const std::string& value); + Builder& setType(const std::string& value); + Builder& setType(const ::android::String16& value); + Builder& setXpanid(const std::vector& value); + Builder& setXpanid(const uint8_t* valuePtr, int32_t valueLen); + Builder& setPanid(int32_t value); + Builder& setChannel(int32_t value); + Builder& setLowpanIdentity(const LowpanIdentity& value); + + LowpanIdentity build(void) const; +private: + LowpanIdentity mIdentity; +}; + +} // namespace lowpan + +} // namespace net + +} // namespace android + +#endif // ANDROID_LOWPAN_IDENTITY_H diff --git a/libandroid_net_lowpan/include/android/net/lowpan/LowpanProvision.h b/libandroid_net_lowpan/include/android/net/lowpan/LowpanProvision.h new file mode 100644 index 0000000..128994c --- /dev/null +++ b/libandroid_net_lowpan/include/android/net/lowpan/LowpanProvision.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef ANDROID_LOWPAN_PROVISION_H +#define ANDROID_LOWPAN_PROVISION_H + +#include +#include +#include + +#include "LowpanIdentity.h" +#include "LowpanCredential.h" + +namespace android { + +namespace net { + +namespace lowpan { + +/* + * C++ implementation of the Java class android.net.lowpan.LowpanProvision + */ +class LowpanProvision : public Parcelable { +public: + LowpanProvision() = default; + virtual ~LowpanProvision() = default; + LowpanProvision(const LowpanProvision& x) = default; + + bool operator==(const LowpanProvision& rhs); + bool operator!=(const LowpanProvision& rhs) { return !(*this == rhs); } + + LowpanProvision(const LowpanIdentity& identity, const LowpanCredential& credential); + LowpanProvision(const LowpanIdentity& identity); + + const LowpanIdentity* getLowpanIdentity() const; + const LowpanCredential* getLowpanCredential() const; + +public: + // Overrides + status_t writeToParcel(Parcel* parcel) const override; + status_t readFromParcel(const Parcel* parcel) override; + +private: + // Data + LowpanIdentity mIdentity; + LowpanCredential mCredential; + bool mHasCredential; +}; + +} // namespace lowpan + +} // namespace net + +} // namespace android + +#endif // ANDROID_LOWPAN_PROVISION_H -- cgit v1.2.3 From e6a1be5f36c91c12ba89bca99233bdb9d7b448e0 Mon Sep 17 00:00:00 2001 From: Robert Quattlebaum Date: Tue, 18 Jul 2017 12:18:58 -0700 Subject: libandroid_net_lowpan: Reintroduce new unit tests for data classes This change introduces new unit tests which confirm that various data classes are being property marshalled between their Java and C++ implementations. This was originally added to platform/frameworks/base via change id I41d590b1e77dc41873c4b9e9bf1b7f1bf859f74e, but that change was reverted (via ag/2553741) due the failure of build 4190632 on the branch `git_wear-master`. Moving these specific tests into this repository avoids this failure case. This change is dependent on the following change id: I70fe6be8d71424e11a537daaa69c3f6cfae8e49d Bug: b/63707448 b/63708348 Change-Id: I41d590b1e77dc41873c4b9e9bf1b7f1bf859f74e Test: These tests both compile and pass --- libandroid_net_lowpan/Android.mk | 2 + libandroid_net_lowpan/tests/Android.mk | 114 ++++++++++++ libandroid_net_lowpan/tests/AndroidManifest.xml | 38 ++++ libandroid_net_lowpan/tests/AndroidTest.xml | 27 +++ libandroid_net_lowpan/tests/README.md | 50 ++++++ .../android/net/lowpan/LowpanBeaconInfoTest.java | 134 ++++++++++++++ .../android/net/lowpan/LowpanChannelInfoTest.java | 78 ++++++++ .../android/net/lowpan/LowpanCredentialTest.java | 92 ++++++++++ .../android/net/lowpan/LowpanIdentityTest.java | 199 +++++++++++++++++++++ .../android/net/lowpan/LowpanProvisionTest.java | 128 +++++++++++++ .../tests/jni/LowpanBeaconInfoTest.cpp | 66 +++++++ .../tests/jni/LowpanBeaconInfoTest.h | 27 +++ .../tests/jni/LowpanChannelInfoTest.cpp | 66 +++++++ .../tests/jni/LowpanChannelInfoTest.h | 27 +++ .../tests/jni/LowpanCredentialTest.cpp | 66 +++++++ .../tests/jni/LowpanCredentialTest.h | 27 +++ .../tests/jni/LowpanIdentityTest.cpp | 66 +++++++ .../tests/jni/LowpanIdentityTest.h | 27 +++ .../tests/jni/LowpanProvisionTest.cpp | 66 +++++++ .../tests/jni/LowpanProvisionTest.h | 27 +++ libandroid_net_lowpan/tests/runtests.sh | 24 +++ 21 files changed, 1351 insertions(+) create mode 100644 libandroid_net_lowpan/tests/Android.mk create mode 100644 libandroid_net_lowpan/tests/AndroidManifest.xml create mode 100644 libandroid_net_lowpan/tests/AndroidTest.xml create mode 100644 libandroid_net_lowpan/tests/README.md create mode 100644 libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanBeaconInfoTest.java create mode 100644 libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanChannelInfoTest.java create mode 100644 libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanCredentialTest.java create mode 100644 libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanIdentityTest.java create mode 100644 libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanProvisionTest.java create mode 100644 libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.cpp create mode 100644 libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.h create mode 100644 libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.cpp create mode 100644 libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.h create mode 100644 libandroid_net_lowpan/tests/jni/LowpanCredentialTest.cpp create mode 100644 libandroid_net_lowpan/tests/jni/LowpanCredentialTest.h create mode 100644 libandroid_net_lowpan/tests/jni/LowpanIdentityTest.cpp create mode 100644 libandroid_net_lowpan/tests/jni/LowpanIdentityTest.h create mode 100644 libandroid_net_lowpan/tests/jni/LowpanProvisionTest.cpp create mode 100644 libandroid_net_lowpan/tests/jni/LowpanProvisionTest.h create mode 100755 libandroid_net_lowpan/tests/runtests.sh diff --git a/libandroid_net_lowpan/Android.mk b/libandroid_net_lowpan/Android.mk index 730d97d..a7bef1f 100644 --- a/libandroid_net_lowpan/Android.mk +++ b/libandroid_net_lowpan/Android.mk @@ -31,3 +31,5 @@ LOCAL_AIDL_INCLUDES += frameworks/base/core/java LOCAL_SRC_FILES += $(call all-Iaidl-files-under, ../../../../base/lowpan/java/android/net/lowpan) LOCAL_SRC_FILES += $(call all-cpp-files-under) include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libandroid_net_lowpan/tests/Android.mk b/libandroid_net_lowpan/tests/Android.mk new file mode 100644 index 0000000..ee44bc5 --- /dev/null +++ b/libandroid_net_lowpan/tests/Android.mk @@ -0,0 +1,114 @@ +# 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. + +LOCAL_PATH:= $(call my-dir) + +# Make test APK +# ============================================================ +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +# This list is generated from the java source files in this module +# The list is a comma separated list of class names with * matching zero or more characters. +# Example: +# Input files: src/com/android/server/lowpan/Test.java src/com/android/server/lowpan/AnotherTest.java +# Generated exclude list: com.android.server.lowpan.Test*,com.android.server.lowpan.AnotherTest* + +# Filter all src files to just java files +local_java_files := $(filter %.java,$(LOCAL_SRC_FILES)) +# Transform java file names into full class names. +# This only works if the class name matches the file name and the directory structure +# matches the package. +local_classes := $(subst /,.,$(patsubst src/%.java,%,$(local_java_files))) +# Utility variables to allow replacing a space with a comma +comma:= , +empty:= +space:= $(empty) $(empty) +# Convert class name list to jacoco exclude list +# This appends a * to all classes and replace the space separators with commas. +# These patterns will match all classes in this module and their inner classes. +jacoco_exclude := $(subst $(space),$(comma),$(patsubst %,%*,$(local_classes))) + +jacoco_include := android.net.lowpan.* + +LOCAL_JACK_COVERAGE_INCLUDE_FILTER := $(jacoco_include) +LOCAL_JACK_COVERAGE_EXCLUDE_FILTER := $(jacoco_exclude) + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + guava \ + mockito-target-minus-junit4 \ + frameworks-base-testutils \ + +LOCAL_JNI_SHARED_LIBRARIES += libframeworkslowpantestsjni +LOCAL_JNI_SHARED_LIBRARIES += libandroid_net_lowpan +LOCAL_JNI_SHARED_LIBRARIES += \ + libbacktrace \ + libbase \ + libbinder \ + libc++ \ + libcutils \ + liblog \ + liblzma \ + libnativehelper \ + libnetdaidl \ + libui \ + libunwind \ + libutils \ + libvndksupport \ + libcrypto \ + libhidl-gen-utils \ + libhidlbase \ + libhidltransport \ + libpackagelistparser \ + libpcre2 \ + libselinux \ + libtinyxml2 \ + libvintf \ + libhwbinder \ + android.hidl.token@1.0 + +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := FrameworksLowpanApiNativeTests +LOCAL_COMPATIBILITY_SUITE := device-tests + +LOCAL_CERTIFICATE := platform +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk +include $(BUILD_PACKAGE) + +######################################################################### +# Build JNI Shared Library +######################################################################### + +LOCAL_PATH:= $(LOCAL_PATH)/jni + +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_CFLAGS := -Wall -Wextra -Werror + +LOCAL_SRC_FILES := $(call all-cpp-files-under) + +LOCAL_SHARED_LIBRARIES += libandroid_net_lowpan +LOCAL_SHARED_LIBRARIES += libbinder +LOCAL_SHARED_LIBRARIES += liblog + +LOCAL_MODULE := libframeworkslowpantestsjni + +include $(BUILD_SHARED_LIBRARY) diff --git a/libandroid_net_lowpan/tests/AndroidManifest.xml b/libandroid_net_lowpan/tests/AndroidManifest.xml new file mode 100644 index 0000000..e9d71ef --- /dev/null +++ b/libandroid_net_lowpan/tests/AndroidManifest.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/libandroid_net_lowpan/tests/AndroidTest.xml b/libandroid_net_lowpan/tests/AndroidTest.xml new file mode 100644 index 0000000..55e5e7f --- /dev/null +++ b/libandroid_net_lowpan/tests/AndroidTest.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/libandroid_net_lowpan/tests/README.md b/libandroid_net_lowpan/tests/README.md new file mode 100644 index 0000000..0711cc1 --- /dev/null +++ b/libandroid_net_lowpan/tests/README.md @@ -0,0 +1,50 @@ +# libandroid_net_lowpan Unit Tests +This package contains unit tests for libandroid_net_lowpan based on the +[Android Testing Support Library](http://developer.android.com/tools/testing-support-library/index.html). +The test cases are built using the [JUnit](http://junit.org/) and [Mockito](http://mockito.org/) +libraries. + +## Running Tests +The easiest way to run tests is simply run + +``` +frameworks/opt/net/lowpan/libandroid_net_lowpan/tests/runtests.sh +``` + +`runtests.sh` will build the test project and all of its dependencies and push the APK to the +connected device. It will then run the tests on the device. + +To pick up changes in framework/base, you will need to: +1. rebuild the framework library 'make -j32' +2. sync over the updated library to the device 'adb sync' +3. restart framework on the device 'adb shell stop' then 'adb shell start' + +To enable syncing data to the device for first time after clean reflash: +1. adb disable-verity +2. adb reboot +3. adb remount + +See below for a few examples of options to limit which tests are run. +See the +[AndroidJUnitRunner Documentation](https://developer.android.com/reference/android/support/test/runner/AndroidJUnitRunner.html) +for more details on the supported options. + +``` +runtests.sh -e package android.net.lowpan +runtests.sh -e class android.net.lowpan.LowpanIdentityTest +``` + +If you manually build and push the test APK to the device you can run tests using + +``` +adb shell am instrument -w 'android.net.lowpan.testnative/android.support.test.runner.AndroidJUnitRunner' +``` + +## Adding Tests +Tests can be added by adding classes to the src directory. JUnit4 style test cases can +be written by simply annotating test methods with `org.junit.Test`. + +## Debugging Tests +If you are trying to debug why tests are not doing what you expected, you can add android log +statements and use logcat to view them. The beginning and end of every tests is automatically logged +with the tag `TestRunner`. diff --git a/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanBeaconInfoTest.java b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanBeaconInfoTest.java new file mode 100644 index 0000000..6dbb3ed --- /dev/null +++ b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanBeaconInfoTest.java @@ -0,0 +1,134 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; + +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanBeaconInfoTest { + + static { + System.loadLibrary("frameworkslowpantestsjni"); + } + + private static native byte[] readAndWriteNative(byte[] inParcel); + + public void testNativeParcelUnparcel(LowpanBeaconInfo original) { + byte[] inParcel = marshall(original); + byte[] outParcel = readAndWriteNative(inParcel); + LowpanBeaconInfo roundTrip = unmarshall(outParcel); + + assertEquals(original, roundTrip); + assertArrayEquals(inParcel, outParcel); + } + + @Test + public void testNativeParcelUnparcel() { + testNativeParcelUnparcel( + new LowpanBeaconInfo.Builder() + .setName("TestNet1") + .setPanid(0x1234) + .setXpanid( + new byte[] { + (byte) 0x00, + (byte) 0x11, + (byte) 0x22, + (byte) 0x33, + (byte) 0x44, + (byte) 0x55, + (byte) 0x66, + (byte) 0x77 + }) + .setType(LowpanInterface.NETWORK_TYPE_THREAD_V1) + .setChannel(15) + .setBeaconAddress( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + }) + .build()); + + testNativeParcelUnparcel( + new LowpanBeaconInfo.Builder() + .setName("TestNet2") + .setPanid(0x5678) + .setXpanid( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + }) + .setType("bork-bork-bork") + .setChannel(16) + .setBeaconAddress( + new byte[] { + (byte) 0x00, + (byte) 0x11, + (byte) 0x22, + (byte) 0x33, + (byte) 0x44, + (byte) 0x55, + (byte) 0x66, + (byte) 0x77 + }) + .setFlag(LowpanBeaconInfo.FLAG_CAN_ASSIST) + .build()); + } + + /** + * Write a {@link LowpanBeaconInfo} into an empty parcel and return the underlying data. + * + * @see unmarshall(byte[]) + */ + private static byte[] marshall(LowpanBeaconInfo addr) { + Parcel p = Parcel.obtain(); + addr.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + return p.marshall(); + } + + /** + * Read raw bytes into a parcel, and read a {@link LowpanBeaconInfo} back out of them. + * + * @see marshall(LowpanBeaconInfo) + */ + private static LowpanBeaconInfo unmarshall(byte[] data) { + Parcel p = Parcel.obtain(); + p.unmarshall(data, 0, data.length); + p.setDataPosition(0); + return LowpanBeaconInfo.CREATOR.createFromParcel(p); + } +} diff --git a/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanChannelInfoTest.java b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanChannelInfoTest.java new file mode 100644 index 0000000..eac4398 --- /dev/null +++ b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanChannelInfoTest.java @@ -0,0 +1,78 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; + +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanChannelInfoTest { + + static { + System.loadLibrary("frameworkslowpantestsjni"); + } + + private static native byte[] readAndWriteNative(byte[] inParcel); + + public void testNativeParcelUnparcel(LowpanChannelInfo original) { + byte[] inParcel = marshall(original); + byte[] outParcel = readAndWriteNative(inParcel); + LowpanChannelInfo roundTrip = unmarshall(outParcel); + + assertEquals(original, roundTrip); + assertArrayEquals(inParcel, outParcel); + } + + @Test + public void testNativeParcelUnparcel() { + int i; + for (i = 1; i < 26; i++) { + testNativeParcelUnparcel(LowpanChannelInfo.getChannelInfoForIeee802154Page0(i)); + } + } + + /** + * Write a {@link LowpanChannelInfo} into an empty parcel and return the underlying data. + * + * @see unmarshall(byte[]) + */ + private static byte[] marshall(LowpanChannelInfo addr) { + Parcel p = Parcel.obtain(); + addr.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + return p.marshall(); + } + + /** + * Read raw bytes into a parcel, and read a {@link LowpanChannelInfo} back out of them. + * + * @see marshall(LowpanChannelInfo) + */ + private static LowpanChannelInfo unmarshall(byte[] data) { + Parcel p = Parcel.obtain(); + p.unmarshall(data, 0, data.length); + p.setDataPosition(0); + return LowpanChannelInfo.CREATOR.createFromParcel(p); + } +} diff --git a/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanCredentialTest.java b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanCredentialTest.java new file mode 100644 index 0000000..26e3334 --- /dev/null +++ b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanCredentialTest.java @@ -0,0 +1,92 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; + +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanCredentialTest { + + static { + System.loadLibrary("frameworkslowpantestsjni"); + } + + private static native byte[] readAndWriteNative(byte[] inParcel); + + public void testNativeParcelUnparcel(LowpanCredential original) { + byte[] inParcel = marshall(original); + byte[] outParcel = readAndWriteNative(inParcel); + LowpanCredential roundTrip = unmarshall(outParcel); + + assertEquals(original, roundTrip); + assertArrayEquals(inParcel, outParcel); + } + + @Test + public void testNativeParcelUnparcel() { + testNativeParcelUnparcel( + LowpanCredential.createMasterKey( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + })); + testNativeParcelUnparcel( + LowpanCredential.createMasterKey( + new byte[] { + (byte) 0x88, (byte) 0x99, (byte) 0xaa, (byte) 0xbb, (byte) 0xcc + }, + 15)); + } + + /** + * Write a {@link LowpanCredential} into an empty parcel and return the underlying data. + * + * @see unmarshall(byte[]) + */ + private static byte[] marshall(LowpanCredential addr) { + Parcel p = Parcel.obtain(); + addr.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + return p.marshall(); + } + + /** + * Read raw bytes into a parcel, and read a {@link LowpanCredential} back out of them. + * + * @see marshall(LowpanCredential) + */ + private static LowpanCredential unmarshall(byte[] data) { + Parcel p = Parcel.obtain(); + p.unmarshall(data, 0, data.length); + p.setDataPosition(0); + return LowpanCredential.CREATOR.createFromParcel(p); + } +} diff --git a/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanIdentityTest.java b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanIdentityTest.java new file mode 100644 index 0000000..1242e55 --- /dev/null +++ b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanIdentityTest.java @@ -0,0 +1,199 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanIdentityTest { + + static { + System.loadLibrary("frameworkslowpantestsjni"); + } + + private static native byte[] readAndWriteNative(byte[] inParcel); + + public void testNativeParcelUnparcel(LowpanIdentity original) { + byte[] inParcel = marshall(original); + byte[] outParcel = readAndWriteNative(inParcel); + LowpanIdentity roundTrip = unmarshall(outParcel); + + assertEquals(original, roundTrip); + assertEquals(original.hashCode(), roundTrip.hashCode()); + assertEquals(original.getName(), roundTrip.getName()); + assertArrayEquals(inParcel, outParcel); + } + + @Test + public void testNativeParcelUnparcel1() { + testNativeParcelUnparcel( + new LowpanIdentity.Builder() + .setName("TestNet1") + .setPanid(0x1234) + .setXpanid( + new byte[] { + (byte) 0x00, + (byte) 0x11, + (byte) 0x22, + (byte) 0x33, + (byte) 0x44, + (byte) 0x55, + (byte) 0x66, + (byte) 0x77 + }) + .setType(LowpanInterface.NETWORK_TYPE_THREAD_V1) + .setChannel(15) + .build()); + } + + @Test + public void testNativeParcelUnparcel2() { + testNativeParcelUnparcel( + new LowpanIdentity.Builder() + .setName("TestNet2") + .setPanid(0x5678) + .setXpanid( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + }) + .setType("bork-bork-bork") + .setChannel(16) + .build()); + } + + @Test + public void testNativeParcelUnparcel3() { + testNativeParcelUnparcel(new LowpanIdentity.Builder().setName("TestNet3").build()); + } + + @Test + public void testNativeParcelUnparcel4() { + testNativeParcelUnparcel(new LowpanIdentity.Builder().build()); + } + + @Test + public void testNativeParcelUnparcel5() { + testNativeParcelUnparcel( + new LowpanIdentity.Builder() + .setRawName( + new byte[] { + (byte) 0x66, + (byte) 0x6F, + (byte) 0x6F, + (byte) 0xC2, + (byte) 0xAD, + (byte) 0xCD, + (byte) 0x8F, + (byte) 0xE1, + (byte) 0xA0, + (byte) 0x86, + (byte) 0xE1, + (byte) 0xA0, + (byte) 0x8B + }) + .build()); + } + + @Test + public void testStringPrep1() { + LowpanIdentity identity = + new LowpanIdentity.Builder() + .setRawName( + new byte[] { + (byte) 0x66, + (byte) 0x6F, + (byte) 0x6F, + (byte) 0x20, + (byte) 0xC2, + (byte) 0xAD, + (byte) 0xCD, + (byte) 0x8F, + (byte) 0xE1, + (byte) 0xA0, + (byte) 0x86, + (byte) 0xE1, + (byte) 0xA0, + (byte) 0x8B + }) + .build(); + + assertFalse(identity.isNameValid()); + } + + @Test + public void testStringPrep2() { + LowpanIdentity identity = + new LowpanIdentity.Builder() + .setRawName( + new byte[] { + (byte) 0x66, (byte) 0x6F, (byte) 0x6F, (byte) 0x20, (byte) 0x6F + }) + .build(); + + assertEquals("foo o", identity.getName()); + assertTrue(identity.isNameValid()); + } + + @Test + public void testStringPrep3() { + LowpanIdentity identity = new LowpanIdentity.Builder().setName("foo o").build(); + + assertTrue(identity.isNameValid()); + assertEquals("foo o", identity.getName()); + } + + /** + * Write a {@link LowpanIdentity} into an empty parcel and return the underlying data. + * + * @see unmarshall(byte[]) + */ + private static byte[] marshall(LowpanIdentity addr) { + Parcel p = Parcel.obtain(); + addr.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + return p.marshall(); + } + + /** + * Read raw bytes into a parcel, and read a {@link LowpanIdentity} back out of them. + * + * @see marshall(LowpanIdentity) + */ + private static LowpanIdentity unmarshall(byte[] data) { + Parcel p = Parcel.obtain(); + p.unmarshall(data, 0, data.length); + p.setDataPosition(0); + return LowpanIdentity.CREATOR.createFromParcel(p); + } +} diff --git a/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanProvisionTest.java b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanProvisionTest.java new file mode 100644 index 0000000..3be2f26 --- /dev/null +++ b/libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanProvisionTest.java @@ -0,0 +1,128 @@ +/* + * 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertArrayEquals; + +import android.os.Parcel; +import android.support.test.runner.AndroidJUnit4; +import android.test.suitebuilder.annotation.SmallTest; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class LowpanProvisionTest { + + static { + System.loadLibrary("frameworkslowpantestsjni"); + } + + private static native byte[] readAndWriteNative(byte[] inParcel); + + public void testNativeParcelUnparcel(LowpanProvision original) { + byte[] inParcel = marshall(original); + byte[] outParcel = readAndWriteNative(inParcel); + LowpanProvision roundTrip = unmarshall(outParcel); + + assertEquals(original, roundTrip); + assertArrayEquals(inParcel, outParcel); + } + + @Test + public void testNativeParcelUnparcel() { + testNativeParcelUnparcel( + new LowpanProvision.Builder() + .setLowpanIdentity( + new LowpanIdentity.Builder() + .setName("TestNet1") + .setPanid(0x1234) + .setXpanid( + new byte[] { + (byte) 0x00, + (byte) 0x11, + (byte) 0x22, + (byte) 0x33, + (byte) 0x44, + (byte) 0x55, + (byte) 0x66, + (byte) 0x77 + }) + .setType(LowpanInterface.NETWORK_TYPE_THREAD_V1) + .setChannel(15) + .build()) + .build()); + testNativeParcelUnparcel( + new LowpanProvision.Builder() + .setLowpanIdentity( + new LowpanIdentity.Builder() + .setName("TestNet2") + .setPanid(0x5678) + .setXpanid( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + }) + .setType("bork-bork-bork") + .setChannel(16) + .build()) + .setLowpanCredential( + LowpanCredential.createMasterKey( + new byte[] { + (byte) 0x88, + (byte) 0x99, + (byte) 0xaa, + (byte) 0xbb, + (byte) 0xcc, + (byte) 0xdd, + (byte) 0xee, + (byte) 0xff + })) + .build()); + } + + /** + * Write a {@link LowpanProvision} into an empty parcel and return the underlying data. + * + * @see unmarshall(byte[]) + */ + private static byte[] marshall(LowpanProvision addr) { + Parcel p = Parcel.obtain(); + addr.writeToParcel(p, /* flags */ 0); + p.setDataPosition(0); + return p.marshall(); + } + + /** + * Read raw bytes into a parcel, and read a {@link LowpanProvision} back out of them. + * + * @see marshall(LowpanProvision) + */ + private static LowpanProvision unmarshall(byte[] data) { + Parcel p = Parcel.obtain(); + p.unmarshall(data, 0, data.length); + p.setDataPosition(0); + return LowpanProvision.CREATOR.createFromParcel(p); + } +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.cpp b/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.cpp new file mode 100644 index 0000000..efc5f18 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +#include + +#include "LowpanBeaconInfoTest.h" + +using android::net::lowpan::LowpanBeaconInfo; + +/** + * Reads exactly one LowpanBeaconInfo from 'parcelData' assuming that it is a Parcel. Any bytes afterward + * are ignored. + */ +static LowpanBeaconInfo unmarshall(JNIEnv* env, jbyteArray parcelData) { + const int length = env->GetArrayLength(parcelData); + + std::unique_ptr bytes(new uint8_t[length]); + env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast(bytes.get())); + + android::Parcel p; + p.setData(bytes.get(), length); + + LowpanBeaconInfo value; + value.readFromParcel(&p); + return value; +} + +/** + * Creates a Java byte[] array and writes the contents of 'addr' to it as a Parcel containing + * exactly one object. + * + * Every LowpanBeaconInfo maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and + * 'unmarshall(e, marshall(e, x))' should be fixed points. + */ +static jbyteArray marshall(JNIEnv* env, const LowpanBeaconInfo& addr) { + android::Parcel p; + addr.writeToParcel(&p); + const int length = p.dataSize(); + + jbyteArray parcelData = env->NewByteArray(length); + env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast(p.data())); + + return parcelData; +} + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanBeaconInfoTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel) { + const LowpanBeaconInfo value = unmarshall(env, inParcel); + return marshall(env, value); +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.h b/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.h new file mode 100644 index 0000000..1ba8eaf --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef _ANDROID_NET_LOWPANBEACONINFOTEST_H_ +#define _ANDROID_NET_LOWPANBEACONINFOTEST_H_ + +#include +#include + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanBeaconInfoTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel); + +#endif // _ANDROID_NET_LOWPANBEACONINFOTEST_H_ diff --git a/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.cpp b/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.cpp new file mode 100644 index 0000000..03bb72a --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +#include + +#include "LowpanChannelInfoTest.h" + +using android::net::lowpan::LowpanChannelInfo; + +/** + * Reads exactly one LowpanChannelInfo from 'parcelData' assuming that it is a Parcel. Any bytes afterward + * are ignored. + */ +static LowpanChannelInfo unmarshall(JNIEnv* env, jbyteArray parcelData) { + const int length = env->GetArrayLength(parcelData); + + std::unique_ptr bytes(new uint8_t[length]); + env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast(bytes.get())); + + android::Parcel p; + p.setData(bytes.get(), length); + + LowpanChannelInfo value; + value.readFromParcel(&p); + return value; +} + +/** + * Creates a Java byte[] array and writes the contents of 'addr' to it as a Parcel containing + * exactly one object. + * + * Every LowpanChannelInfo maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and + * 'unmarshall(e, marshall(e, x))' should be fixed points. + */ +static jbyteArray marshall(JNIEnv* env, const LowpanChannelInfo& addr) { + android::Parcel p; + addr.writeToParcel(&p); + const int length = p.dataSize(); + + jbyteArray parcelData = env->NewByteArray(length); + env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast(p.data())); + + return parcelData; +} + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanChannelInfoTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel) { + const LowpanChannelInfo value = unmarshall(env, inParcel); + return marshall(env, value); +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.h b/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.h new file mode 100644 index 0000000..3b29a90 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef _ANDROID_NET_LOWPANCHANNELINFOTEST_H_ +#define _ANDROID_NET_LOWPANCHANNELINFOTEST_H_ + +#include +#include + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanChannelInfoTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel); + +#endif // _ANDROID_NET_LOWPANCHANNELINFOTEST_H_ diff --git a/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.cpp b/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.cpp new file mode 100644 index 0000000..fc860b2 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +#include + +#include "LowpanCredentialTest.h" + +using android::net::lowpan::LowpanCredential; + +/** + * Reads exactly one LowpanCredential from 'parcelData' assuming that it is a Parcel. Any bytes afterward + * are ignored. + */ +static LowpanCredential unmarshall(JNIEnv* env, jbyteArray parcelData) { + const int length = env->GetArrayLength(parcelData); + + std::unique_ptr bytes(new uint8_t[length]); + env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast(bytes.get())); + + android::Parcel p; + p.setData(bytes.get(), length); + + LowpanCredential value; + value.readFromParcel(&p); + return value; +} + +/** + * Creates a Java byte[] array and writes the contents of 'addr' to it as a Parcel containing + * exactly one object. + * + * Every LowpanCredential maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and + * 'unmarshall(e, marshall(e, x))' should be fixed points. + */ +static jbyteArray marshall(JNIEnv* env, const LowpanCredential& addr) { + android::Parcel p; + addr.writeToParcel(&p); + const int length = p.dataSize(); + + jbyteArray parcelData = env->NewByteArray(length); + env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast(p.data())); + + return parcelData; +} + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanCredentialTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel) { + const LowpanCredential value = unmarshall(env, inParcel); + return marshall(env, value); +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.h b/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.h new file mode 100644 index 0000000..9dd9889 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanCredentialTest.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef _ANDROID_NET_LOWPANCREDENTIALTEST_H_ +#define _ANDROID_NET_LOWPANCREDENTIALTEST_H_ + +#include +#include + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanCredentialTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel); + +#endif // _ANDROID_NET_LOWPANCREDENTIALTEST_H_ diff --git a/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.cpp b/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.cpp new file mode 100644 index 0000000..1a9ad33 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +#include + +#include "LowpanIdentityTest.h" + +using android::net::lowpan::LowpanIdentity; + +/** + * Reads exactly one LowpanIdentity from 'parcelData' assuming that it is a Parcel. Any bytes afterward + * are ignored. + */ +static LowpanIdentity unmarshall(JNIEnv* env, jbyteArray parcelData) { + const int length = env->GetArrayLength(parcelData); + + std::unique_ptr bytes(new uint8_t[length]); + env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast(bytes.get())); + + android::Parcel p; + p.setData(bytes.get(), length); + + LowpanIdentity value; + value.readFromParcel(&p); + return value; +} + +/** + * Creates a Java byte[] array and writes the contents of 'addr' to it as a Parcel containing + * exactly one object. + * + * Every LowpanIdentity maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and + * 'unmarshall(e, marshall(e, x))' should be fixed points. + */ +static jbyteArray marshall(JNIEnv* env, const LowpanIdentity& addr) { + android::Parcel p; + addr.writeToParcel(&p); + const int length = p.dataSize(); + + jbyteArray parcelData = env->NewByteArray(length); + env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast(p.data())); + + return parcelData; +} + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanIdentityTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel) { + const LowpanIdentity value = unmarshall(env, inParcel); + return marshall(env, value); +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.h b/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.h new file mode 100644 index 0000000..1d2c465 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanIdentityTest.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef _ANDROID_NET_LOWPANIDENTITYTEST_H_ +#define _ANDROID_NET_LOWPANIDENTITYTEST_H_ + +#include +#include + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanIdentityTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel); + +#endif // _ANDROID_NET_LOWPANIDENTITYTEST_H_ diff --git a/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.cpp b/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.cpp new file mode 100644 index 0000000..95f64b6 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.cpp @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include + +#include + +#include "LowpanProvisionTest.h" + +using android::net::lowpan::LowpanProvision; + +/** + * Reads exactly one LowpanProvision from 'parcelData' assuming that it is a Parcel. Any bytes afterward + * are ignored. + */ +static LowpanProvision unmarshall(JNIEnv* env, jbyteArray parcelData) { + const int length = env->GetArrayLength(parcelData); + + std::unique_ptr bytes(new uint8_t[length]); + env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast(bytes.get())); + + android::Parcel p; + p.setData(bytes.get(), length); + + LowpanProvision value; + value.readFromParcel(&p); + return value; +} + +/** + * Creates a Java byte[] array and writes the contents of 'addr' to it as a Parcel containing + * exactly one object. + * + * Every LowpanProvision maps to a unique parcel object, so both 'marshall(e, unmarshall(e, x))' and + * 'unmarshall(e, marshall(e, x))' should be fixed points. + */ +static jbyteArray marshall(JNIEnv* env, const LowpanProvision& addr) { + android::Parcel p; + addr.writeToParcel(&p); + const int length = p.dataSize(); + + jbyteArray parcelData = env->NewByteArray(length); + env->SetByteArrayRegion(parcelData, 0, length, reinterpret_cast(p.data())); + + return parcelData; +} + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanProvisionTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel) { + const LowpanProvision value = unmarshall(env, inParcel); + return marshall(env, value); +} diff --git a/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.h b/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.h new file mode 100644 index 0000000..49211b5 --- /dev/null +++ b/libandroid_net_lowpan/tests/jni/LowpanProvisionTest.h @@ -0,0 +1,27 @@ +/* + * 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. + */ + +#ifndef _ANDROID_NET_LOWPANPROVISIONTEST_H_ +#define _ANDROID_NET_LOWPANPROVISIONTEST_H_ + +#include +#include + +extern "C" +JNIEXPORT jbyteArray Java_android_net_lowpan_LowpanProvisionTest_readAndWriteNative(JNIEnv* env, jclass, + jbyteArray inParcel); + +#endif // _ANDROID_NET_LOWPANPROVISIONTEST_H_ diff --git a/libandroid_net_lowpan/tests/runtests.sh b/libandroid_net_lowpan/tests/runtests.sh new file mode 100755 index 0000000..c3cc4da --- /dev/null +++ b/libandroid_net_lowpan/tests/runtests.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +if [ -z $ANDROID_BUILD_TOP ]; then + echo "You need to source and lunch before you can use this script" + exit 1 +fi + +echo "Running tests" + +set -e # fail early + +echo "+ mmma -j32 $ANDROID_BUILD_TOP/frameworks/opt/net/lowpan/libandroid_net_lowpan/tests" +# NOTE Don't actually run the command above since this shell doesn't inherit functions from the +# caller. +make -j32 -C $ANDROID_BUILD_TOP -f build/core/main.mk MODULES-IN-frameworks-opt-net-lowpan-libandroid_net_lowpan-tests + +set -x # print commands + +adb root +adb wait-for-device + +adb install -r -g "$OUT/data/app/FrameworksLowpanApiNativeTests/FrameworksLowpanApiNativeTests.apk" + +adb shell am instrument -w "$@" 'android.net.lowpan.testnative/android.support.test.runner.AndroidJUnitRunner' -- cgit v1.2.3