summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2017-12-06 11:52:02 -0800
committerXin Li <delphij@google.com>2017-12-06 14:24:50 -0800
commitd65ab13260cca31e9fb33bab97b0d7fd7ecd65ca (patch)
tree6aa83f202600cf75d6a27bca41ca63393bca6432
parent7bf3ff0542b52af0693d7c093159bcd8691a10a5 (diff)
parente6a1be5f36c91c12ba89bca99233bdb9d7b448e0 (diff)
downloadlowpan-d65ab13260cca31e9fb33bab97b0d7fd7ecd65ca.tar.gz
DO NOT MERGE: Merge Oreo MR1 into masterandroid-wear-8.0.0_r1
Exempt-From-Owner-Approval: Changes already landed internally Change-Id: I4bdc4ff1c0313e76927996807892650a842396ba
-rw-r--r--.gitattributes5
-rw-r--r--.gitignore2
-rw-r--r--Android.mk19
-rw-r--r--command/Android.mk36
-rw-r--r--command/java/com/android/commands/lowpan/LowpanCtl.java433
-rwxr-xr-xcommand/lowpanctl6
-rw-r--r--libandroid_net_lowpan/Android.mk35
-rw-r--r--libandroid_net_lowpan/LowpanBeaconInfo.cpp218
-rw-r--r--libandroid_net_lowpan/LowpanChannelInfo.cpp114
-rw-r--r--libandroid_net_lowpan/LowpanCredential.cpp149
-rw-r--r--libandroid_net_lowpan/LowpanIdentity.cpp189
-rw-r--r--libandroid_net_lowpan/LowpanProvision.cpp121
-rw-r--r--libandroid_net_lowpan/include/android/net/lowpan/LowpanBeaconInfo.h101
-rw-r--r--libandroid_net_lowpan/include/android/net/lowpan/LowpanChannelInfo.h64
-rw-r--r--libandroid_net_lowpan/include/android/net/lowpan/LowpanCredential.h72
-rw-r--r--libandroid_net_lowpan/include/android/net/lowpan/LowpanIdentity.h90
-rw-r--r--libandroid_net_lowpan/include/android/net/lowpan/LowpanProvision.h69
-rw-r--r--libandroid_net_lowpan/tests/Android.mk114
-rw-r--r--libandroid_net_lowpan/tests/AndroidManifest.xml38
-rw-r--r--libandroid_net_lowpan/tests/AndroidTest.xml27
-rw-r--r--libandroid_net_lowpan/tests/README.md50
-rw-r--r--libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanBeaconInfoTest.java134
-rw-r--r--libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanChannelInfoTest.java78
-rw-r--r--libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanCredentialTest.java92
-rw-r--r--libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanIdentityTest.java199
-rw-r--r--libandroid_net_lowpan/tests/java/android/net/lowpan/LowpanProvisionTest.java128
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.cpp66
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanBeaconInfoTest.h27
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.cpp66
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanChannelInfoTest.h27
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanCredentialTest.cpp66
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanCredentialTest.h27
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanIdentityTest.cpp66
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanIdentityTest.h27
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanProvisionTest.cpp66
-rw-r--r--libandroid_net_lowpan/tests/jni/LowpanProvisionTest.h27
-rwxr-xr-xlibandroid_net_lowpan/tests/runtests.sh24
-rw-r--r--service/Android.mk29
-rw-r--r--service/java/com/android/server/lowpan/LowpanInterfaceTracker.java637
-rw-r--r--service/java/com/android/server/lowpan/LowpanService.java45
-rw-r--r--service/java/com/android/server/lowpan/LowpanServiceImpl.java284
-rwxr-xr-xtests/commandtest.sh45
-rwxr-xr-xtests/prepdevice.sh38
43 files changed, 4150 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..bc24d41
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +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/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6ef218
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+.idea
+
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/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..8e36841
--- /dev/null
+++ b/command/java/com/android/commands/lowpan/LowpanCtl.java
@@ -0,0 +1,433 @@
+/*
+ * 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.net.LinkAddress;
+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"
+ + "options:\n"
+ + " -I / --interface <iface-name> ..... Interface Name\n"
+ + "subcommands:\n"
+ + " lowpanctl status\n"
+ + " lowpanctl form\n"
+ + " lowpanctl join\n"
+ + " lowpanctl attach\n"
+ + " lowpanctl leave\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> ............. Network Name\n"
+ + " -p / --panid <panid> .............. PANID\n"
+ + " -c / --channel <channel> .......... Channel Index\n"
+ + " -x / --xpanid <xpanid> ............ XPANID\n"
+ + " -k / --master-key <master-key> .... Master Key\n"
+ + " --master-key-index <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 {
+ 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")) {
+ runAttach();
+ break;
+ } 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();
+ break;
+ } else if (op.equals("form")) {
+ runForm();
+ break;
+ } else if (op.equals("leave")) {
+ runLeave();
+ 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 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<String, Object> 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.equals("--help")) {
+ throwCommandError("");
+ } 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 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()
+ + " with provided credential");
+ } else {
+ System.out.println("Forming " + provision.getLowpanIdentity());
+ }
+
+ getLowpanInterface().form(provision);
+
+ System.out.println("Formed.");
+ }
+
+ 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");
+ }
+
+ if (iface.isConnected()) {
+ sb.append(" CONNECTED");
+ }
+
+ if (iface.isCommissioned()) {
+ sb.append(" COMMISSIONED");
+ }
+
+ sb
+ .append("\n\t")
+ .append(getLowpanInterface().getLowpanIdentity());
+
+ for (LinkAddress addr : iface.getLinkAddresses()) {
+ sb.append("\n\t").append(addr);
+ }
+
+ sb.append("\n");
+ System.out.println(sb.toString());
+ }
+
+ 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() {
+ 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 "$@"
diff --git a/libandroid_net_lowpan/Android.mk b/libandroid_net_lowpan/Android.mk
new file mode 100644
index 0000000..a7bef1f
--- /dev/null
+++ b/libandroid_net_lowpan/Android.mk
@@ -0,0 +1,35 @@
+#
+# 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)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
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 <android/net/lowpan/LowpanBeaconInfo.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+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<uint8_t>& 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<uint8_t>& 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<int32_t>::const_iterator iter;
+ std::set<int32_t>::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 <android/net/lowpan/LowpanChannelInfo.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+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 <android/net/lowpan/LowpanCredential.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+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<uint8_t>& masterKey, int masterKeyIndex)
+{
+ return LowpanCredential::initMasterKey(out, &masterKey.front(), masterKey.size(), masterKeyIndex);
+}
+
+status_t LowpanCredential::initMasterKey(LowpanCredential& out, const std::vector<uint8_t>& masterKey)
+{
+ return LowpanCredential::initMasterKey(out, masterKey, 0);
+}
+
+bool LowpanCredential::isMasterKey() const {
+ return mMasterKey.size() > 0;
+}
+
+bool LowpanCredential::getMasterKey(std::vector<uint8_t>* 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 <android/net/lowpan/LowpanIdentity.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+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<uint8_t>* 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<uint8_t>& 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<int8_t> 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<int8_t> 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 <android/net/lowpan/LowpanProvision.h>
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+#include <utils/Errors.h>
+
+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 <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <set>
+
+#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<uint8_t> mBeaconAddress;
+ std::set<int32_t> 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<uint8_t>& 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<uint8_t>& 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<uint8_t> mBeaconAddress;
+ std::set<int32_t> 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 <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <string>
+
+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 <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+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<uint8_t>& masterKey, int32_t masterKeyIndex);
+ static status_t initMasterKey(LowpanCredential& out, const std::vector<uint8_t>& 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<uint8_t>* 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<uint8_t> 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 <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#include <string>
+
+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<uint8_t>* 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<uint8_t> 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<uint8_t>& 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 <binder/Parcelable.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+
+#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
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ 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
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.net.lowpan.testnative">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:label="LowpanTestDummyLabel"
+ android:name="LowpanTestDummyName">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.net.lowpan.testnative"
+ android:label="Frameworks LoWPAN API Native Tests">
+ </instrumentation>
+
+</manifest>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs Frameworks LoWPAN API Native Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="FrameworksLowpanApiTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksLowpanApiNativeTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.net.lowpan.testnative" />
+ <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+ </test>
+</configuration>
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 <memory>
+
+#include <binder/Parcel.h>
+
+#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<uint8_t> bytes(new uint8_t[length]);
+ env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(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<const jbyte*>(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 <jni.h>
+#include <android/net/lowpan/LowpanBeaconInfo.h>
+
+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 <memory>
+
+#include <binder/Parcel.h>
+
+#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<uint8_t> bytes(new uint8_t[length]);
+ env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(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<const jbyte*>(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 <jni.h>
+#include <android/net/lowpan/LowpanChannelInfo.h>
+
+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 <memory>
+
+#include <binder/Parcel.h>
+
+#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<uint8_t> bytes(new uint8_t[length]);
+ env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(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<const jbyte*>(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 <jni.h>
+#include <android/net/lowpan/LowpanCredential.h>
+
+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 <memory>
+
+#include <binder/Parcel.h>
+
+#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<uint8_t> bytes(new uint8_t[length]);
+ env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(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<const jbyte*>(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 <jni.h>
+#include <android/net/lowpan/LowpanIdentity.h>
+
+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 <memory>
+
+#include <binder/Parcel.h>
+
+#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<uint8_t> bytes(new uint8_t[length]);
+ env->GetByteArrayRegion(parcelData, 0, length, reinterpret_cast<jbyte*>(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<const jbyte*>(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 <jni.h>
+#include <android/net/lowpan/LowpanProvision.h>
+
+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'
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..89b058c
--- /dev/null
+++ b/service/java/com/android/server/lowpan/LowpanInterfaceTracker.java
@@ -0,0 +1,637 @@
+/*
+ * 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.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.InitialConfiguration;
+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.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;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+/** 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.
+ *
+ * <p>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;
+ 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 final IpManager mIpManager;
+ private final IpManager.Callback mIpManagerCallback = new IpManagerCallback();
+
+ // 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 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 {
+ @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);
+ }
+ }
+
+ 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 {
+ @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);
+
+ 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(mObtainingIpState);
+ break;
+ case LowpanInterface.STATE_FAULT:
+ transitionTo(mFaultState);
+ break;
+ }
+ }
+ retValue = HANDLED;
+ break;
+ }
+ return retValue;
+ }
+
+ @Override
+ public void exit() {
+
+ 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.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) {
+ mHwAddr = HexDump.toHexString(hwAddr);
+ }
+ }
+
+ 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.
+
+ 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;
+
+ case CMD_PROVISIONING_FAILURE:
+ Log.i(TAG, "Provisioning Failure: " + message.obj.toString());
+ 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() {
+ 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() {
+ bringUpNetworkAgent();
+ 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 ObtainingIpState extends State {
+ @Override
+ public void enter() {
+ InitialConfiguration initialConfiguration = new InitialConfiguration();
+
+ try {
+ for (LinkAddress address : mLowpanInterface.getLinkAddresses()) {
+ if (DBG) {
+ Log.i(TAG, "Adding link address: " + address);
+ }
+
+ initialConfiguration.ipAddresses.add(address);
+
+ IpPrefix prefix = new IpPrefix(address.getAddress(), address.getPrefixLength());
+
+ 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
+ public boolean processMessage(Message message) {
+
+ switch (message.what) {
+ case CMD_PROVISIONING_SUCCESS:
+ Log.i(TAG, "Provisioning Success: " + message.obj.toString());
+ transitionTo(mConnectedState);
+ return HANDLED;
+ }
+ return NOT_HANDLED;
+ }
+
+ @Override
+ public void exit() {}
+ }
+
+ class ConnectedState extends State {
+ @Override
+ public void enter() {
+ mNetworkInfo.setDetailedState(DetailedState.CONNECTED, null, mHwAddr);
+ 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(Context context, ILowpanInterface ifaceService, Looper looper) {
+ super(TAG, looper);
+
+ if (DBG) {
+ Log.i(TAG, "LowpanInterfaceTracker() begin");
+ }
+
+ setDbg(DBG);
+ setLogRecSize(NUM_LOG_RECS_NORMAL);
+ setLogOnlyTransitions(false);
+
+ mILowpanInterface = ifaceService;
+ mLowpanInterface = new LowpanInterface(context, ifaceService, looper);
+ mContext = context;
+
+ mInterfaceName = mLowpanInterface.getName();
+
+ mLinkProperties = new LinkProperties();
+ mLinkProperties.setInterfaceName(mInterfaceName);
+
+ // Initialize capabilities
+ mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_LOWPAN);
+ mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+ mNetworkCapabilities.setLinkUpstreamBandwidthKbps(100);
+ mNetworkCapabilities.setLinkDownstreamBandwidthKbps(100);
+
+ // 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(mObtainingIpState, mAttachedState);
+ 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);
+ }
+ };
+
+ mIpManager = new IpManager(mContext, mInterfaceName, mIpManagerCallback);
+
+ 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..07677e3
--- /dev/null
+++ b/service/java/com/android/server/lowpan/LowpanServiceImpl.java
@@ -0,0 +1,284 @@
+/*
+ * 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.os.ServiceSpecificException;
+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<ILowpanManagerListener> mListenerSet = new HashSet<>();
+ private final Map<String, LowpanInterfaceTracker> 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<String, LowpanInterfaceTracker> 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 | ServiceSpecificException x) {
+ // Don't let misbehavior of a listener
+ // crash the system service.
+ Log.e(TAG, "Exception caught: " + x);
+
+ // TODO: Consider removing the listener...?
+ }
+ }
+ }
+ }
+
+ 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 | ServiceSpecificException x) {
+ // Don't let misbehavior of a listener
+ // crash the system service.
+ Log.e(TAG, "Exception caught: " + x);
+
+ // TODO: Consider removing the listener...?
+ }
+ }
+ }
+ }
+
+ 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 | ServiceSpecificException x) {
+ // Don't let misbehavior of an interface
+ // crash the system service.
+ Log.e(TAG, "Exception caught: " + x);
+ return;
+ }
+
+ final LowpanInterfaceTracker previous;
+ final LowpanInterfaceTracker agent;
+
+ synchronized (mInterfaceMap) {
+ previous = mInterfaceMap.get(name);
+
+ agent = new LowpanInterfaceTracker(mContext, lowpanInterface, 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 | ServiceSpecificException x) {
+ // Directly fetching the name failed, so fall back to
+ // a reverse lookup.
+ synchronized (mInterfaceMap) {
+ for (Map.Entry<String, LowpanInterfaceTracker> 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) {
+ // We only get this exception if listener has already died.
+ 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?
+ }
+ }
+}
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.
+