am c95668c5: am 88daa997: am c38ffecc: Merge "Moving BTtraffic from experiment location to here" into cw-d-mr1-dev
* commit 'c95668c5d4c3d29f8b9d1c0202415e5cbea47416': Moving BTtraffic from experiment location to here
This commit is contained in:
16
core/tests/BTtraffic/Android.mk
Normal file
16
core/tests/BTtraffic/Android.mk
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
|
|
||||||
|
LOCAL_RESOURCE_DIR := \
|
||||||
|
$(LOCAL_PATH)/res
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := bttraffic
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
|
|
||||||
|
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||||
22
core/tests/BTtraffic/AndroidManifest.xml
Normal file
22
core/tests/BTtraffic/AndroidManifest.xml
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.google.android.experimental.bttraffic" >
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
|
||||||
|
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="18"
|
||||||
|
android:targetSdkVersion="18"
|
||||||
|
/>
|
||||||
|
<application
|
||||||
|
android:allowBackup="false"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<service
|
||||||
|
android:name=".BTtraffic"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true" >
|
||||||
|
</service>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
45
core/tests/BTtraffic/README
Normal file
45
core/tests/BTtraffic/README
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
This is a tool to generate classic Bluetooth traffic with specified period and package size.
|
||||||
|
Together with the SvcMonitor, which will be called automatically in this android service, can be
|
||||||
|
used to measure the CPU usage from the Java layer Bluetooth code and the underlying system service
|
||||||
|
com.android.bluetooth.
|
||||||
|
|
||||||
|
1. Server (Listener) - Client (Sender) model. Both run as an Android service.
|
||||||
|
2. No pairing needed. Communicate via unsecured RFcomm. Client establishes the connection by
|
||||||
|
providing the MAC addr of the server.
|
||||||
|
3. Bluetooth has to be turned on on both side.
|
||||||
|
4. Client can configure the traffic by specifying the transfer period and package size.
|
||||||
|
5. A separate monitor process will be automatically forked and will be reading from /proc file
|
||||||
|
system to calculate the cpu usage. The measurement is updated once per second.
|
||||||
|
6. The monitor process (com.google.android.experimental.svcmonitor/.ScvMonitor) can be run as an
|
||||||
|
independent service to measure cpu usage on any similarly configured tests (e.g. wifi, BLE). Refer
|
||||||
|
to SvcMonitor's README for usage and details.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
To instal the test:
|
||||||
|
On both the server and client device, install the 2 apk:
|
||||||
|
$ adb install $OUT/system/app/bttraffic/bttraffic.apk
|
||||||
|
$ adb install $OUT/system/app/svcmonitor/svcmonitor.apk
|
||||||
|
|
||||||
|
To start the service on the SERVER side:
|
||||||
|
$ adb shell am startservice -a start --ez ack true \
|
||||||
|
com.google.android.experimental.bttraffic/.BTtraffic
|
||||||
|
|
||||||
|
To start the service on the CLIENT side:
|
||||||
|
$ adb shell am startservice -a start \
|
||||||
|
-e addr "F8:A9:D0:A8:74:8E" --ei size 1000 --ei period 15 \
|
||||||
|
com.google.android.experimental.bttraffic/.BTtraffic
|
||||||
|
|
||||||
|
To stop the test:
|
||||||
|
On either the server or client:
|
||||||
|
$ adb shell am startservice -a stop \
|
||||||
|
com.google.android.experimental.bttraffic/.BTtraffic
|
||||||
|
|
||||||
|
To look at the data:
|
||||||
|
$ adb logcat | grep bttraffic
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-e addr: MAC addr of the server, in uppercase letter.
|
||||||
|
--ei size: package size, unit: byte; default: 1024, MAX: 20MB
|
||||||
|
--ei period: system sleep time between sending each package, unit: ms, default: 5000
|
||||||
|
** if -1 is provided, client will only send the package once.
|
||||||
|
--ez ack: whether acknowledge is required (true/false)
|
||||||
3
core/tests/BTtraffic/res/values/strings.xml
Normal file
3
core/tests/BTtraffic/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Bluetooth Test</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,328 @@
|
|||||||
|
package com.google.android.experimental.bttraffic;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.bluetooth.BluetoothAdapter;
|
||||||
|
import android.bluetooth.BluetoothDevice;
|
||||||
|
import android.bluetooth.BluetoothServerSocket;
|
||||||
|
import android.bluetooth.BluetoothSocket;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.lang.Exception;
|
||||||
|
import java.lang.Runtime;
|
||||||
|
import java.lang.RuntimeException;
|
||||||
|
import java.lang.Process;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class BTtraffic extends Service {
|
||||||
|
public static final String TAG = "bttraffic";
|
||||||
|
static final String SERVICE_NAME = "bttraffic";
|
||||||
|
static final String SYS_SERVICE_NAME = "com.android.bluetooth";
|
||||||
|
static final UUID SERVICE_UUID = UUID.fromString("5e8945b0-1234-5432-a5e2-0800200c9a67");
|
||||||
|
volatile Thread mWorkerThread;
|
||||||
|
volatile boolean isShuttingDown = false;
|
||||||
|
volatile boolean isServer = false;
|
||||||
|
|
||||||
|
public BTtraffic() {}
|
||||||
|
|
||||||
|
static void safeClose(Closeable closeable) {
|
||||||
|
try {
|
||||||
|
closeable.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Unable to close resource.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
if (intent == null) {
|
||||||
|
stopSelf();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ("stop".equals(intent.getAction())) {
|
||||||
|
stopService();
|
||||||
|
} else if ("start".equals(intent.getAction())) {
|
||||||
|
startWorker(intent);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "unknown action: + " + intent.getAction());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startWorker(Intent intent) {
|
||||||
|
if (mWorkerThread != null) {
|
||||||
|
Log.d(TAG, "worker thread already active");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
isShuttingDown = false;
|
||||||
|
String remoteAddr = intent.getStringExtra("addr");
|
||||||
|
Log.d(TAG, "startWorker: addr=" + remoteAddr);
|
||||||
|
Runnable worker =
|
||||||
|
remoteAddr == null
|
||||||
|
? new ListenerRunnable(this, intent)
|
||||||
|
: new SenderRunnable(this, remoteAddr, intent);
|
||||||
|
isServer = remoteAddr == null ? true: false;
|
||||||
|
mWorkerThread = new Thread(worker, "BTtrafficWorker");
|
||||||
|
try {
|
||||||
|
startMonitor();
|
||||||
|
Log.d(TAG, "Monitor service started");
|
||||||
|
mWorkerThread.start();
|
||||||
|
Log.d(TAG, "Worker thread started");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(TAG, "Failed to start service", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startMonitor()
|
||||||
|
throws Exception {
|
||||||
|
if (isServer) {
|
||||||
|
Log.d(TAG, "Start monitor on server");
|
||||||
|
String[] startmonitorCmd = {
|
||||||
|
"/system/bin/am",
|
||||||
|
"startservice",
|
||||||
|
"-a", "start",
|
||||||
|
"-e", "java", SERVICE_NAME,
|
||||||
|
"-e", "hal", SYS_SERVICE_NAME,
|
||||||
|
"com.google.android.experimental.svcmonitor/.SvcMonitor"
|
||||||
|
};
|
||||||
|
Process ps = new ProcessBuilder()
|
||||||
|
.command(startmonitorCmd)
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "No need to start SvcMonitor on client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopMonitor()
|
||||||
|
throws Exception {
|
||||||
|
if (isServer) {
|
||||||
|
Log.d(TAG, "StopMonitor on server");
|
||||||
|
String[] stopmonitorCmd = {
|
||||||
|
"/system/bin/am",
|
||||||
|
"startservice",
|
||||||
|
"-a", "stop",
|
||||||
|
"com.google.android.experimental.svcmonitor/.SvcMonitor"
|
||||||
|
};
|
||||||
|
Process ps = new ProcessBuilder()
|
||||||
|
.command(stopmonitorCmd)
|
||||||
|
.redirectErrorStream(true)
|
||||||
|
.start();
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "No need to stop Svcmonitor on client");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopService() {
|
||||||
|
if (mWorkerThread == null) {
|
||||||
|
Log.d(TAG, "no active thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isShuttingDown = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
stopMonitor();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(TAG, "Unable to stop SvcMonitor!", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Thread.currentThread() != mWorkerThread) {
|
||||||
|
mWorkerThread.interrupt();
|
||||||
|
Log.d(TAG, "Interrupting thread");
|
||||||
|
try {
|
||||||
|
mWorkerThread.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.d(TAG, "Unable to join thread!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mWorkerThread = null;
|
||||||
|
stopSelf();
|
||||||
|
Log.d(TAG, "Service stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ListenerRunnable implements Runnable {
|
||||||
|
private final BTtraffic bttraffic;
|
||||||
|
private final boolean sendAck;
|
||||||
|
private Intent intent;
|
||||||
|
private final int maxbuffersize = 20 * 1024 * 1024;
|
||||||
|
|
||||||
|
public ListenerRunnable(BTtraffic bttraffic, Intent intent) {
|
||||||
|
this.bttraffic = bttraffic;
|
||||||
|
this.sendAck = intent.getBooleanExtra("ack", true);
|
||||||
|
this.intent = intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
BluetoothServerSocket serverSocket;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "getting server socket");
|
||||||
|
serverSocket = BluetoothAdapter.getDefaultAdapter()
|
||||||
|
.listenUsingInsecureRfcommWithServiceRecord(
|
||||||
|
SERVICE_NAME, SERVICE_UUID);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "error creating server socket, stopping thread");
|
||||||
|
bttraffic.stopService();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "got server socket, starting accept loop");
|
||||||
|
BluetoothSocket socket = null;
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "accepting");
|
||||||
|
socket = serverSocket.accept();
|
||||||
|
|
||||||
|
if (!Thread.interrupted()) {
|
||||||
|
Log.d(TAG, "accepted, listening");
|
||||||
|
doListening(socket.getInputStream(), socket.getOutputStream());
|
||||||
|
Log.d(TAG, "listen finished");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "error while accepting or listening", e);
|
||||||
|
} finally {
|
||||||
|
Log.d(TAG, "Linster interruped");
|
||||||
|
Log.d(TAG, "closing socket and stopping service");
|
||||||
|
safeClose(serverSocket);
|
||||||
|
safeClose(socket);
|
||||||
|
if (!bttraffic.isShuttingDown)
|
||||||
|
bttraffic.stopService();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doListening(InputStream inputStream, OutputStream outputStream)
|
||||||
|
throws IOException {
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(maxbuffersize);
|
||||||
|
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
readBytesIntoBuffer(inputStream, byteBuffer, 4);
|
||||||
|
byteBuffer.flip();
|
||||||
|
int length = byteBuffer.getInt();
|
||||||
|
if (Thread.interrupted())
|
||||||
|
break;
|
||||||
|
readBytesIntoBuffer(inputStream, byteBuffer, length);
|
||||||
|
|
||||||
|
if (sendAck)
|
||||||
|
outputStream.write(0x55);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readBytesIntoBuffer(InputStream inputStream, ByteBuffer byteBuffer, int numToRead)
|
||||||
|
throws IOException {
|
||||||
|
byteBuffer.clear();
|
||||||
|
while (true) {
|
||||||
|
int position = byteBuffer.position();
|
||||||
|
int remaining = numToRead - position;
|
||||||
|
if (remaining == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
int count = inputStream.read(byteBuffer.array(), position, remaining);
|
||||||
|
if (count < 0) {
|
||||||
|
throw new IOException("read the EOF");
|
||||||
|
}
|
||||||
|
byteBuffer.position(position + count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SenderRunnable implements Runnable {
|
||||||
|
private final BTtraffic bttraffic;
|
||||||
|
private final String remoteAddr;
|
||||||
|
private final int pkgsize, period;
|
||||||
|
private final int defaultpkgsize = 1024;
|
||||||
|
private final int defaultperiod = 5000;
|
||||||
|
private static ByteBuffer lengthBuffer = ByteBuffer.allocate(4);
|
||||||
|
|
||||||
|
public SenderRunnable(BTtraffic bttraffic, String remoteAddr, Intent intent) {
|
||||||
|
this.bttraffic = bttraffic;
|
||||||
|
this.remoteAddr = remoteAddr;
|
||||||
|
this.pkgsize = intent.getIntExtra("size", defaultpkgsize);
|
||||||
|
this.period = intent.getIntExtra("period", defaultperiod);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
BluetoothDevice device = null;
|
||||||
|
try {
|
||||||
|
device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(remoteAddr);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
Log.d(TAG, "Invalid BT MAC address!\n");
|
||||||
|
}
|
||||||
|
if (device == null) {
|
||||||
|
Log.d(TAG, "can't find matching device, stopping thread and service");
|
||||||
|
bttraffic.stopService();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothSocket socket = null;
|
||||||
|
try {
|
||||||
|
Log.d(TAG, "connecting to device with MAC addr: " + remoteAddr);
|
||||||
|
socket = device.createInsecureRfcommSocketToServiceRecord(SERVICE_UUID);
|
||||||
|
socket.connect();
|
||||||
|
Log.d(TAG, "connected, starting to send");
|
||||||
|
doSending(socket.getOutputStream());
|
||||||
|
Log.d(TAG, "send stopped, stopping service");
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.d(TAG, "error while sending", e);
|
||||||
|
} finally {
|
||||||
|
Log.d(TAG, "finishing, closing thread and service");
|
||||||
|
safeClose(socket);
|
||||||
|
if (!bttraffic.isShuttingDown)
|
||||||
|
bttraffic.stopService();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSending(OutputStream outputStream) throws IOException {
|
||||||
|
Log.w(TAG, "doSending");
|
||||||
|
try {
|
||||||
|
Random random = new Random(System.currentTimeMillis());
|
||||||
|
|
||||||
|
byte[] bytes = new byte[pkgsize];
|
||||||
|
random.nextBytes(bytes);
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
writeBytes(outputStream, bytes.length);
|
||||||
|
outputStream.write(bytes, 0, bytes.length);
|
||||||
|
if (period < 0)
|
||||||
|
break;
|
||||||
|
if (period == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SystemClock.sleep(period);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Sender interrupted");
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "doSending got error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void writeBytes(OutputStream outputStream, int value) throws IOException {
|
||||||
|
lengthBuffer.putInt(value);
|
||||||
|
lengthBuffer.flip();
|
||||||
|
outputStream.write(lengthBuffer.array(), lengthBuffer.position(), lengthBuffer.limit());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
16
core/tests/SvcMonitor/Android.mk
Normal file
16
core/tests/SvcMonitor/Android.mk
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
LOCAL_PATH:= $(call my-dir)
|
||||||
|
include $(CLEAR_VARS)
|
||||||
|
|
||||||
|
LOCAL_MODULE_TAGS := optional
|
||||||
|
|
||||||
|
LOCAL_SRC_FILES := $(call all-java-files-under, src)
|
||||||
|
|
||||||
|
LOCAL_RESOURCE_DIR := \
|
||||||
|
$(LOCAL_PATH)/res
|
||||||
|
|
||||||
|
LOCAL_PACKAGE_NAME := svcmonitor
|
||||||
|
LOCAL_CERTIFICATE := platform
|
||||||
|
|
||||||
|
include $(BUILD_PACKAGE)
|
||||||
|
|
||||||
|
include $(call all-makefiles-under,$(LOCAL_PATH))
|
||||||
21
core/tests/SvcMonitor/AndroidManifest.xml
Normal file
21
core/tests/SvcMonitor/AndroidManifest.xml
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.google.android.experimental.svcmonitor" >
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
|
||||||
|
|
||||||
|
<uses-sdk
|
||||||
|
android:minSdkVersion="18"
|
||||||
|
android:targetSdkVersion="18"
|
||||||
|
/>
|
||||||
|
<application
|
||||||
|
android:allowBackup="false"
|
||||||
|
android:label="@string/app_name" >
|
||||||
|
<service
|
||||||
|
android:name=".SvcMonitor"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="true" >
|
||||||
|
</service>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
||||||
27
core/tests/SvcMonitor/README
Normal file
27
core/tests/SvcMonitor/README
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
This Android service measures CPU usage of a program and an underlying system service it relies on.
|
||||||
|
An example of this would be an android app XYZ communicates to some other device via Bluetooth. The
|
||||||
|
SvcMonitor service can monitor the CPU usage of XYZ and com.android.bluetooth.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
To start the service:
|
||||||
|
$ adb shell am startservice -a start \
|
||||||
|
-e java XYZ -e hal com.android.bluetooth \
|
||||||
|
com.google.android.experimental.svcmonitor/.SvcMonitor
|
||||||
|
|
||||||
|
To stop the service:
|
||||||
|
$ adb shell am startservice -a stop \
|
||||||
|
com.google.android.experimental.svcmonitor/.SvcMonitor
|
||||||
|
|
||||||
|
To stop the service config:
|
||||||
|
$ adb shell am startservice -a change \
|
||||||
|
-e java NewName -e hal NewService \
|
||||||
|
com.google.android.experimental.svcmonitor/.SvcMonitor
|
||||||
|
|
||||||
|
To monitor the data:
|
||||||
|
$ adb logcat | grep XYZ
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-e java NameOfProgram: any running process’s name.
|
||||||
|
-e hal NameOfSysService: name of the system service the previous process relies on.
|
||||||
|
--ei period: period between each measurement (frequency). Unit: ms, Default:1000, Min: 100
|
||||||
3
core/tests/SvcMonitor/res/values/strings.xml
Normal file
3
core/tests/SvcMonitor/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">Bluetooth Test</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,209 @@
|
|||||||
|
package com.google.android.experimental.svcmonitor;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.lang.Runnable;
|
||||||
|
import java.lang.Thread;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class SvcMonitor extends Service {
|
||||||
|
public static final String TAG = "svcmonitor";
|
||||||
|
String javaProc, halProc;
|
||||||
|
volatile Thread tMonitor;
|
||||||
|
int period;
|
||||||
|
|
||||||
|
public SvcMonitor() {};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
if (intent == null) {
|
||||||
|
stopSelf();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Starting SvcMonitor");
|
||||||
|
if ("stop".equals(intent.getAction())) {
|
||||||
|
stopService();
|
||||||
|
} else if ("start".equals(intent.getAction())) {
|
||||||
|
startMonitor(intent);
|
||||||
|
} else if ("change".equals(intent.getAction())) {
|
||||||
|
changeConfig(intent);
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "unknown action: + " + intent.getAction());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeConfig(Intent intent) {
|
||||||
|
if (tMonitor == null) {
|
||||||
|
Log.d(TAG, "Service not active. Start service first");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stopThread();
|
||||||
|
startMonitor(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startMonitor(Intent intent) {
|
||||||
|
if (tMonitor != null) {
|
||||||
|
Log.d(TAG, "thread already active");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
javaProc = intent.getStringExtra("java");
|
||||||
|
halProc = intent.getStringExtra("hal");
|
||||||
|
period = intent.getIntExtra("period", 1000);
|
||||||
|
if (javaProc == null || halProc == null || period < 100) {
|
||||||
|
Log.d(TAG, "Failed starting monitor, invalid arguments.");
|
||||||
|
stopSelf();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Runnable monitor = new MonitorRunnable(this);
|
||||||
|
tMonitor = new Thread(monitor);
|
||||||
|
tMonitor.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopService() {
|
||||||
|
stopThread();
|
||||||
|
stopSelf();
|
||||||
|
Log.d(TAG, "SvcMonitor stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void stopThread() {
|
||||||
|
if (tMonitor == null) {
|
||||||
|
Log.d(TAG, "no active thread");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "interrupting monitor thread");
|
||||||
|
tMonitor.interrupt();
|
||||||
|
try {
|
||||||
|
tMonitor.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
Log.d(TAG, "Unable to finish monitor thread");
|
||||||
|
}
|
||||||
|
tMonitor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
throw new UnsupportedOperationException("Not yet implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class MonitorRunnable implements Runnable {
|
||||||
|
long java_time_old, hal_time_old, cpu_time_old = -1;
|
||||||
|
String javaPID, halPID;
|
||||||
|
SvcMonitor svcmonitor;
|
||||||
|
static String javaProcTAG;
|
||||||
|
int period;
|
||||||
|
|
||||||
|
public MonitorRunnable(SvcMonitor svcmonitor) {
|
||||||
|
this.svcmonitor = svcmonitor;
|
||||||
|
this.period = svcmonitor.period;
|
||||||
|
javaPID = getPIDof(svcmonitor.javaProc);
|
||||||
|
halPID = getPIDof(svcmonitor.halProc);
|
||||||
|
java_time_old = getPsTime(javaPID);
|
||||||
|
hal_time_old = getPsTime(halPID);
|
||||||
|
cpu_time_old = getPsTime("");
|
||||||
|
javaProcTAG = String.valueOf(svcmonitor.javaProc.toCharArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (halPID.isEmpty() || javaPID.isEmpty()) {
|
||||||
|
Log.d(javaProcTAG, "No such process: " +
|
||||||
|
(halPID.isEmpty() ? svcmonitor.halProc : svcmonitor.javaProc));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (!Thread.interrupted()) {
|
||||||
|
calculateUsage();
|
||||||
|
SystemClock.sleep(period);
|
||||||
|
}
|
||||||
|
Log.d(TAG, "Stopping monitor thread");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void calculateUsage() {
|
||||||
|
long java_time = getPsTime(javaPID);
|
||||||
|
long hal_time = getPsTime(halPID);
|
||||||
|
long cpu_time = getPsTime("");
|
||||||
|
|
||||||
|
if (cpu_time_old >= 0) {
|
||||||
|
float java_diff = (float) (java_time - java_time_old);
|
||||||
|
float hal_diff = (float) (hal_time - hal_time_old);
|
||||||
|
float cpu_diff = (float) (cpu_time - cpu_time_old);
|
||||||
|
Log.w(javaProcTAG, "\n----------------\n");
|
||||||
|
Log.w(javaProcTAG, "JAVA level CPU: "
|
||||||
|
+ (java_diff * 100.0 / cpu_diff) + "%\n");
|
||||||
|
Log.w(javaProcTAG, " HAL level CPU: "
|
||||||
|
+ (hal_diff * 100.0 / cpu_diff) + "%\n");
|
||||||
|
Log.w(javaProcTAG, " SYS level CPU: "
|
||||||
|
+ ((java_diff + hal_diff) * 100.0 / cpu_diff) + "%\n");
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Waiting for status\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
java_time_old = java_time;
|
||||||
|
hal_time_old = hal_time;
|
||||||
|
cpu_time_old = cpu_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPIDof(String psName) {
|
||||||
|
String pid = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
String[] cmd = {"/system/bin/sh", "-c", "ps | grep " + psName};
|
||||||
|
Process ps = Runtime.getRuntime().exec(cmd);
|
||||||
|
BufferedReader in = new BufferedReader(
|
||||||
|
new InputStreamReader(ps.getInputStream()));
|
||||||
|
String temp = in.readLine();
|
||||||
|
if (temp == null || temp.isEmpty())
|
||||||
|
throw new IOException("No such process: " + psName);
|
||||||
|
pid = temp.split(" +")[1];
|
||||||
|
in.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(javaProcTAG, "Error finding PID of process: " + psName + "\n", e);
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getPsTime(String pid) {
|
||||||
|
String psStat = getPsStat("/" + pid);
|
||||||
|
String[] statBreakDown = psStat.split(" +");
|
||||||
|
long psTime;
|
||||||
|
|
||||||
|
if (pid.isEmpty()) {
|
||||||
|
psTime = Long.parseLong(statBreakDown[1])
|
||||||
|
+ Long.parseLong(statBreakDown[2])
|
||||||
|
+ Long.parseLong(statBreakDown[3])
|
||||||
|
+ Long.parseLong(statBreakDown[4]);
|
||||||
|
} else {
|
||||||
|
psTime = Long.parseLong(statBreakDown[13])
|
||||||
|
+ Long.parseLong(statBreakDown[14]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return psTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getPsStat(String psname) {
|
||||||
|
String stat = "";
|
||||||
|
try {
|
||||||
|
FileInputStream fs = new FileInputStream("/proc" + psname + "/stat");
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(fs));
|
||||||
|
stat = br.readLine();
|
||||||
|
fs.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.d(TAG, "Error retreiving stat. \n");
|
||||||
|
}
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user