diff options
author | Xin Li <delphij@google.com> | 2017-12-06 11:52:02 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2017-12-06 14:24:50 -0800 |
commit | d65ab13260cca31e9fb33bab97b0d7fd7ecd65ca (patch) | |
tree | 6aa83f202600cf75d6a27bca41ca63393bca6432 /command | |
parent | 7bf3ff0542b52af0693d7c093159bcd8691a10a5 (diff) | |
parent | e6a1be5f36c91c12ba89bca99233bdb9d7b448e0 (diff) | |
download | lowpan-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
Diffstat (limited to 'command')
-rw-r--r-- | command/Android.mk | 36 | ||||
-rw-r--r-- | command/java/com/android/commands/lowpan/LowpanCtl.java | 433 | ||||
-rwxr-xr-x | command/lowpanctl | 6 |
3 files changed, 475 insertions, 0 deletions
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 "$@" |