From 8b3b98d62234fb12625c00feb63ac9cc21931b59 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Mon, 29 Aug 2011 20:11:07 -0400 Subject: [PATCH] New Serial Manager API: SerialManager: provides access to serial ports SerialPort: for reading and writing data to and from serial ports IO with both array based and direct ByteBuffers is supported. Accessing serial ports requires android.permission.SERIAL_PORT permission Each platform must configure list of supported serial ports in the config_serialPorts resource overlay (this is needed to prevent apps from accidentally accessing the bluetooth or other system UARTs). In addition, the platform uevent.rc file must set the owner to the /dev/tty* files to "system" so the framework can access the port. Change-Id: I6afa78ceacf08486aaebced4156ecd2e33051879 Signed-off-by: Mike Lockwood --- Android.mk | 1 + core/java/android/app/ContextImpl.java | 8 + core/java/android/content/Context.java | 11 + core/java/android/hardware/ISerialManager.aidl | 29 +++ core/java/android/hardware/SerialManager.java | 88 +++++++ core/java/android/hardware/SerialPort.java | 122 ++++++++++ core/jni/Android.mk | 1 + core/jni/AndroidRuntime.cpp | 2 + core/jni/android_hardware_SerialPort.cpp | 266 +++++++++++++++++++++ core/res/AndroidManifest.xml | 7 + core/res/res/values/config.xml | 6 + core/res/res/values/strings.xml | 5 + .../java/com/android/server/SerialService.java | 58 +++++ services/java/com/android/server/SystemServer.java | 10 + services/jni/Android.mk | 1 + services/jni/com_android_server_SerialService.cpp | 82 +++++++ services/jni/onload.cpp | 2 + 17 files changed, 699 insertions(+) create mode 100644 core/java/android/hardware/ISerialManager.aidl create mode 100644 core/java/android/hardware/SerialManager.java create mode 100644 core/java/android/hardware/SerialPort.java create mode 100644 core/jni/android_hardware_SerialPort.cpp create mode 100644 services/java/com/android/server/SerialService.java create mode 100644 services/jni/com_android_server_SerialService.cpp diff --git a/Android.mk b/Android.mk index d4dc08847ae3..a8c46126f7d0 100644 --- a/Android.mk +++ b/Android.mk @@ -109,6 +109,7 @@ LOCAL_SRC_FILES += \ core/java/android/content/pm/IPackageMoveObserver.aidl \ core/java/android/content/pm/IPackageStatsObserver.aidl \ core/java/android/database/IContentObserver.aidl \ + core/java/android/hardware/ISerialManager.aidl \ core/java/android/hardware/usb/IUsbManager.aidl \ core/java/android/net/IConnectivityManager.aidl \ core/java/android/net/INetworkManagementEventObserver.aidl \ diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 21397040357f..404ba87f4dbd 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -42,7 +42,9 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; +import android.hardware.ISerialManager; import android.hardware.SensorManager; +import android.hardware.SerialManager; import android.hardware.usb.IUsbManager; import android.hardware.usb.UsbManager; import android.location.CountryDetector; @@ -427,6 +429,12 @@ class ContextImpl extends Context { return new UsbManager(ctx, IUsbManager.Stub.asInterface(b)); }}); + registerService(SERIAL_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + IBinder b = ServiceManager.getService(SERIAL_SERVICE); + return new SerialManager(ctx, ISerialManager.Stub.asInterface(b)); + }}); + registerService(VIBRATOR_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return new Vibrator(); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 46712a9d041e..d104344e0389 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1780,6 +1780,17 @@ public abstract class Context { public static final String USB_SERVICE = "usb"; /** + * Use with {@link #getSystemService} to retrieve a {@link + * android.hardware.SerialManager} for access to serial ports. + * + * @see #getSystemService + * @see android.harware.SerialManager + * + * @hide + */ + public static final String SERIAL_SERVICE = "serial"; + + /** * Determine whether the given permission is allowed for a particular * process and user ID running in the system. * diff --git a/core/java/android/hardware/ISerialManager.aidl b/core/java/android/hardware/ISerialManager.aidl new file mode 100644 index 000000000000..74d30f7afefe --- /dev/null +++ b/core/java/android/hardware/ISerialManager.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2011 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.hardware; + +import android.os.ParcelFileDescriptor; + +/** @hide */ +interface ISerialManager +{ + /* Returns a list of all available serial ports */ + String[] getSerialPorts(); + + /* Returns a file descriptor for the serial port. */ + ParcelFileDescriptor openSerialPort(String name); +} diff --git a/core/java/android/hardware/SerialManager.java b/core/java/android/hardware/SerialManager.java new file mode 100644 index 000000000000..c5e1c2bcb9de --- /dev/null +++ b/core/java/android/hardware/SerialManager.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2011 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.hardware; + +import android.app.PendingIntent; +import android.content.Context; +import android.os.Bundle; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.os.SystemProperties; +import android.util.Log; + +import java.io.IOException; +import java.util.HashMap; + +/** + * @hide + */ +public class SerialManager { + private static final String TAG = "SerialManager"; + + private final Context mContext; + private final ISerialManager mService; + + /** + * {@hide} + */ + public SerialManager(Context context, ISerialManager service) { + mContext = context; + mService = service; + } + + /** + * Returns a string array containing the names of available serial ports + * + * @return names of available serial ports + */ + public String[] getSerialPorts() { + try { + return mService.getSerialPorts(); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException in getSerialPorts", e); + return null; + } + } + + /** + * Opens and returns the {@link android.hardware.SerialPort} with the given name. + * The speed of the serial port must be one of: + * 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, + * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, + * 1500000, 2000000, 2500000, 3000000, 3500000 or 4000000 + * + * @param name of the serial port + * @param speed at which to open the serial port + * @return the serial port + */ + public SerialPort openSerialPort(String name, int speed) throws IOException { + try { + ParcelFileDescriptor pfd = mService.openSerialPort(name); + if (pfd != null) { + SerialPort port = new SerialPort(name); + port.open(pfd, speed); + return port; + } else { + throw new IOException("Could not open serial port " + name); + } + } catch (RemoteException e) { + Log.e(TAG, "exception in UsbManager.openDevice", e); + } + return null; + } +} diff --git a/core/java/android/hardware/SerialPort.java b/core/java/android/hardware/SerialPort.java new file mode 100644 index 000000000000..0889790fa4b5 --- /dev/null +++ b/core/java/android/hardware/SerialPort.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2011 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.hardware; + +import android.os.ParcelFileDescriptor; +import android.util.Log; + +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.ByteBuffer; + +/** + * @hide + */ +public class SerialPort { + + private static final String TAG = "SerialPort"; + + // used by the JNI code + private int mNativeContext; + private final String mName; + private ParcelFileDescriptor mFileDescriptor; + + /** + * SerialPort should only be instantiated by SerialManager + * @hide + */ + public SerialPort(String name) { + mName = name; + } + + /** + * SerialPort should only be instantiated by SerialManager + * Speed must be one of 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, + * 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, + * 1500000, 2000000, 2500000, 3000000, 3500000, 4000000 + * + * @hide + */ + public void open(ParcelFileDescriptor pfd, int speed) throws IOException { + native_open(pfd.getFileDescriptor(), speed); + mFileDescriptor = pfd; + } + + /** + * Closes the serial port + */ + public void close() throws IOException { + if (mFileDescriptor != null) { + mFileDescriptor.close(); + mFileDescriptor = null; + } + native_close(); + } + + /** + * Returns the name of the serial port + * + * @return the serial port's name + */ + public String getName() { + return mName; + } + + /** + * Reads data into the provided buffer + * + * @param buffer to read into + * @return number of bytes read + */ + public int read(ByteBuffer buffer) throws IOException { + if (buffer.isDirect()) { + return native_read_direct(buffer, buffer.remaining()); + } else if (buffer.hasArray()) { + return native_read_array(buffer.array(), buffer.remaining()); + } else { + throw new IllegalArgumentException("buffer is not direct and has no array"); + } + } + + /** + * Writes data from provided buffer + * + * @param buffer to write + * @param length number of bytes to write + */ + public void write(ByteBuffer buffer, int length) throws IOException { + if (buffer.isDirect()) { + native_write_direct(buffer, length); + } else if (buffer.hasArray()) { + native_write_array(buffer.array(), length); + } else { + throw new IllegalArgumentException("buffer is not direct and has no array"); + } + } + + private native void native_open(FileDescriptor pfd, int speed) throws IOException; + private native void native_close(); + private native int native_read_array(byte[] buffer, int length) throws IOException; + private native int native_read_direct(ByteBuffer buffer, int length) throws IOException; + private native void native_write_array(byte[] buffer, int length) throws IOException; + private native void native_write_direct(ByteBuffer buffer, int length) throws IOException; +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index aece5f0b6e7e..bc6489bd415e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -128,6 +128,7 @@ LOCAL_SRC_FILES:= \ android_media_ToneGenerator.cpp \ android_hardware_Camera.cpp \ android_hardware_SensorManager.cpp \ + android_hardware_SerialPort.cpp \ android_hardware_UsbDevice.cpp \ android_hardware_UsbDeviceConnection.cpp \ android_hardware_UsbRequest.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index dd7dd867d5f2..12ad5fc3f907 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -76,6 +76,7 @@ extern int register_android_opengl_jni_GLES20(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); +extern int register_android_hardware_SerialPort(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); extern int register_android_hardware_UsbDeviceConnection(JNIEnv *env); extern int register_android_hardware_UsbRequest(JNIEnv *env); @@ -1162,6 +1163,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_os_ZygoteInit), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_SensorManager), + REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_UsbDevice), REG_JNI(register_android_hardware_UsbDeviceConnection), REG_JNI(register_android_hardware_UsbRequest), diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp new file mode 100644 index 000000000000..792211595f2d --- /dev/null +++ b/core/jni/android_hardware_SerialPort.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2011 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 "SerialPortJNI" + +#include "utils/Log.h" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include +#include +#include +#include +#include + +using namespace android; + +static jfieldID field_context; + +static void +android_hardware_SerialPort_open(JNIEnv *env, jobject thiz, jobject fileDescriptor, jint speed) +{ + switch (speed) { + case 50: + speed = B50; + break; + case 75: + speed = B75; + break; + case 110: + speed = B110; + break; + case 134: + speed = B134; + break; + case 150: + speed = B150; + break; + case 200: + speed = B200; + break; + case 300: + speed = B300; + break; + case 600: + speed = B600; + break; + case 1200: + speed = B1200; + break; + case 1800: + speed = B1800; + break; + case 2400: + speed = B2400; + break; + case 4800: + speed = B4800; + break; + case 9600: + speed = B9600; + break; + case 19200: + speed = B19200; + break; + case 38400: + speed = B38400; + break; + case 57600: + speed = B57600; + break; + case 115200: + speed = B115200; + break; + case 230400: + speed = B230400; + break; + case 460800: + speed = B460800; + break; + case 500000: + speed = B500000; + break; + case 576000: + speed = B576000; + break; + case 921600: + speed = B921600; + break; + case 1000000: + speed = B1000000; + break; + case 1152000: + speed = B1152000; + break; + case 1500000: + speed = B1500000; + break; + case 2000000: + speed = B2000000; + break; + case 2500000: + speed = B2500000; + break; + case 3000000: + speed = B3000000; + break; + case 3500000: + speed = B3500000; + break; + case 4000000: + speed = B4000000; + break; + default: + jniThrowException(env, "java/lang/IllegalArgumentException", + "Unsupported serial port speed"); + return; + } + + int fd = jniGetFDFromFileDescriptor(env, fileDescriptor); + // duplicate the file descriptor, since ParcelFileDescriptor will eventually close its copy + fd = dup(fd); + if (fd < 0) { + jniThrowException(env, "java/io/IOException", "Could not open serial port"); + return; + } + env->SetIntField(thiz, field_context, fd); + + struct termios tio; + if (tcgetattr(fd, &tio)) + memset(&tio, 0, sizeof(tio)); + + tio.c_cflag = speed | CS8 | CLOCAL | CREAD; + tio.c_iflag = IGNPAR; + tio.c_lflag = 0; /* turn of CANON, ECHO*, etc */ + /* no timeout but request at least one character per read */ + tio.c_cc[VTIME] = 0; + tio.c_cc[VMIN] = 1; + tcsetattr(fd, TCSANOW, &tio); + tcflush(fd, TCIFLUSH); +} + +static void +android_hardware_SerialPort_close(JNIEnv *env, jobject thiz) +{ + int fd = env->GetIntField(thiz, field_context); + close(fd); + env->SetIntField(thiz, field_context, -1); +} + +static jint +android_hardware_SerialPort_read_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + jbyte* buf = (jbyte *)malloc(length); + if (!buf) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return -1; + } + + int ret = read(fd, buf, length); + if (ret > 0) { + // copy data from native buffer to Java buffer + env->SetByteArrayRegion(buffer, 0, ret, buf); + } + + free(buf); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); + return ret; +} + +static jint +android_hardware_SerialPort_read_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + + jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer); + if (!buf) { + jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct"); + return -1; + } + + int ret = read(fd, buf, length); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); + return ret; +} + +static void +android_hardware_SerialPort_write_array(JNIEnv *env, jobject thiz, jbyteArray buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + jbyte* buf = (jbyte *)malloc(length); + if (!buf) { + jniThrowException(env, "java/lang/OutOfMemoryError", NULL); + return; + } + env->GetByteArrayRegion(buffer, 0, length, buf); + + jint ret = write(fd, buf, length); + free(buf); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); +} + +static void +android_hardware_SerialPort_write_direct(JNIEnv *env, jobject thiz, jobject buffer, jint length) +{ + int fd = env->GetIntField(thiz, field_context); + + jbyte* buf = (jbyte *)env->GetDirectBufferAddress(buffer); + if (!buf) { + jniThrowException(env, "java/lang/IllegalArgumentException", "ByteBuffer not direct"); + return; + } + int ret = write(fd, buf, length); + if (ret < 0) + jniThrowException(env, "java/io/IOException", NULL); +} + +static JNINativeMethod method_table[] = { + {"native_open", "(Ljava/io/FileDescriptor;I)V", + (void *)android_hardware_SerialPort_open}, + {"native_close", "()V", (void *)android_hardware_SerialPort_close}, + {"native_read_array", "([BI)I", + (void *)android_hardware_SerialPort_read_array}, + {"native_read_direct", "(Ljava/nio/ByteBuffer;I)I", + (void *)android_hardware_SerialPort_read_direct}, + {"native_write_array", "([BI)V", + (void *)android_hardware_SerialPort_write_array}, + {"native_write_direct", "(Ljava/nio/ByteBuffer;I)V", + (void *)android_hardware_SerialPort_write_direct}, +}; + +int register_android_hardware_SerialPort(JNIEnv *env) +{ + jclass clazz = env->FindClass("android/hardware/SerialPort"); + if (clazz == NULL) { + LOGE("Can't find android/hardware/SerialPort"); + return -1; + } + field_context = env->GetFieldID(clazz, "mNativeContext", "I"); + if (field_context == NULL) { + LOGE("Can't find SerialPort.mNativeContext"); + return -1; + } + + return AndroidRuntime::registerNativeMethods(env, "android/hardware/SerialPort", + method_table, NELEM(method_table)); +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 540c65a7812d..2d053d077142 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1454,6 +1454,13 @@ android:description="@string/permdesc_bindPackageVerifier" android:protectionLevel="signature" /> + + + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index b155b8036d20..d427b7b3740e 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -301,6 +301,12 @@ + + + + 0 diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index a3e460e82350..1680596d341b 100755 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -2228,6 +2228,11 @@ Allows the holder to make requests of package verifiers. Should never be needed for normal applications. + + access serial ports + + Allows the holder to access serial ports using the SerialManager API. + Do you want the browser to remember this password? diff --git a/services/java/com/android/server/SerialService.java b/services/java/com/android/server/SerialService.java new file mode 100644 index 000000000000..5d2b2a0d3304 --- /dev/null +++ b/services/java/com/android/server/SerialService.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 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 an + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.hardware.ISerialManager; +import android.os.ParcelFileDescriptor; + +import java.io.File; +import java.util.ArrayList; + +public class SerialService extends ISerialManager.Stub { + + private final Context mContext; + private final String[] mSerialPorts; + + public SerialService(Context context) { + mContext = context; + mSerialPorts = context.getResources().getStringArray( + com.android.internal.R.array.config_serialPorts); + } + + public String[] getSerialPorts() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); + + ArrayList ports = new ArrayList(); + for (int i = 0; i < mSerialPorts.length; i++) { + String path = mSerialPorts[i]; + if (new File(path).exists()) { + ports.add(path); + } + } + String[] result = new String[ports.size()]; + ports.toArray(result); + return result; + } + + public ParcelFileDescriptor openSerialPort(String path) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.SERIAL_PORT, null); + return native_open(path); + } + + private native ParcelFileDescriptor native_open(String path); +} diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index fb00fa42048c..7a1bd0ae18b0 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -125,6 +125,7 @@ class ServerThread extends Thread { BluetoothA2dpService bluetoothA2dp = null; DockObserver dock = null; UsbService usb = null; + SerialService serial = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; ThrottleService throttle = null; @@ -483,6 +484,15 @@ class ServerThread extends Thread { } try { + Slog.i(TAG, "Serial Service"); + // Serial port support + serial = new SerialService(context); + ServiceManager.addService(Context.SERIAL_SERVICE, serial); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting SerialService", e); + } + + try { Slog.i(TAG, "UI Mode Manager Service"); // Listen for UI mode changes uiMode = new UiModeManagerService(context); diff --git a/services/jni/Android.mk b/services/jni/Android.mk index 6fa5dfa969b5..c63b84df88b7 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES:= \ com_android_server_InputWindowHandle.cpp \ com_android_server_LightsService.cpp \ com_android_server_PowerManagerService.cpp \ + com_android_server_SerialService.cpp \ com_android_server_SystemServer.cpp \ com_android_server_UsbDeviceManager.cpp \ com_android_server_UsbHostManager.cpp \ diff --git a/services/jni/com_android_server_SerialService.cpp b/services/jni/com_android_server_SerialService.cpp new file mode 100644 index 000000000000..4bb7e36c627a --- /dev/null +++ b/services/jni/com_android_server_SerialService.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 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 "SerialServiceJNI" +#include "utils/Log.h" + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" + +#include +#include +#include + +namespace android +{ + +static struct parcel_file_descriptor_offsets_t +{ + jclass mClass; + jmethodID mConstructor; +} gParcelFileDescriptorOffsets; + +static jobject android_server_SerialService_open(JNIEnv *env, jobject thiz, jstring path) +{ + const char *pathStr = env->GetStringUTFChars(path, NULL); + + int fd = open(pathStr, O_RDWR | O_NOCTTY); + if (fd < 0) { + LOGE("could not open %s", pathStr); + env->ReleaseStringUTFChars(path, pathStr); + return NULL; + } + env->ReleaseStringUTFChars(path, pathStr); + + jobject fileDescriptor = jniCreateFileDescriptor(env, fd); + if (fileDescriptor == NULL) { + return NULL; + } + return env->NewObject(gParcelFileDescriptorOffsets.mClass, + gParcelFileDescriptorOffsets.mConstructor, fileDescriptor); +} + + +static JNINativeMethod method_table[] = { + { "native_open", "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", + (void*)android_server_SerialService_open }, +}; + +int register_android_server_SerialService(JNIEnv *env) +{ + jclass clazz = env->FindClass("com/android/server/SerialService"); + if (clazz == NULL) { + LOGE("Can't find com/android/server/SerialService"); + return -1; + } + + clazz = env->FindClass("android/os/ParcelFileDescriptor"); + LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor"); + gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz); + gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "", "(Ljava/io/FileDescriptor;)V"); + LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL, + "Unable to find constructor for android.os.ParcelFileDescriptor"); + + return jniRegisterNativeMethods(env, "com/android/server/SerialService", + method_table, NELEM(method_table)); +} + +}; diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 4178039fa55a..0a935259a6c0 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -27,6 +27,7 @@ int register_android_server_InputWindowHandle(JNIEnv* env); int register_android_server_InputManager(JNIEnv* env); int register_android_server_LightsService(JNIEnv* env); int register_android_server_PowerManagerService(JNIEnv* env); +int register_android_server_SerialService(JNIEnv* env); int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); @@ -49,6 +50,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) LOG_ASSERT(env, "Could not retrieve the env!"); register_android_server_PowerManagerService(env); + register_android_server_SerialService(env); register_android_server_InputApplicationHandle(env); register_android_server_InputWindowHandle(env); register_android_server_InputManager(env); -- 2.11.0