Loading core/java/android/hardware/serial/ISerialManager.aidl +7 −5 Original line number Diff line number Diff line Loading @@ -37,8 +37,10 @@ interface ISerialManager { * @param flags open flags {@code SerialPort.OPEN_FLAG_*} that define read/write mode and * other options. * @param exclusive whether the app needs exclusive access with TIOCEXCL(2const) * @param packageName the package name of the calling application * @param callback the receiver of the operation result. * @throws IllegalArgumentException if the set of flags is not correct. */ void requestOpen(in String portName, in int flags, in boolean exclusive, in ISerialPortResponseCallback callback); void requestOpen(in String portName, in int flags, in boolean exclusive, in String packageName, in ISerialPortResponseCallback callback); } core/java/android/hardware/serial/ISerialPortResponseCallback.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -32,8 +32,10 @@ oneway interface ISerialPortResponseCallback { ERROR_READING_DRIVERS = 0, // Serial port with the given name does not exist. ERROR_PORT_NOT_FOUND = 1, // SecurityException due to access denied. ERROR_ACCESS_DENIED = 2, // ErrnoException while opening the serial port. ERROR_OPENING_PORT = 2, ERROR_OPENING_PORT = 3, } /** Loading core/java/android/hardware/serial/SerialManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import java.util.concurrent.Executor; public final class SerialManager { private static final String TAG = "SerialManager"; @SuppressWarnings("unused") private final @NonNull Context mContext; private final @NonNull ISerialManager mService; Loading @@ -68,7 +67,7 @@ public final class SerialManager { List<SerialPortInfo> infos = mService.getSerialPorts(); List<SerialPort> ports = new ArrayList<>(infos.size()); for (int i = 0; i < infos.size(); i++) { ports.add(new SerialPort(infos.get(i), mService)); ports.add(new SerialPort(mContext, infos.get(i), mService)); } return Collections.unmodifiableList(ports); } catch (RemoteException e) { Loading Loading @@ -131,7 +130,7 @@ public final class SerialManager { private class SerialPortServiceListener extends ISerialPortListener.Stub { @Override public void onSerialPortConnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); SerialPort port = new SerialPort(mContext, info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); Loading @@ -147,7 +146,7 @@ public final class SerialManager { @Override public void onSerialPortDisconnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); SerialPort port = new SerialPort(mContext, info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); Loading core/java/android/hardware/serial/SerialPort.java +7 −5 Original line number Diff line number Diff line Loading @@ -23,13 +23,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.os.OutcomeReceiver; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.system.ErrnoException; import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; import java.lang.annotation.Retention; import java.util.Objects; Loading Loading @@ -92,12 +91,14 @@ public final class SerialPort { */ public static final int OPEN_FLAG_SYNC = 1 << 20; private final @NonNull Context mContext; private final @NonNull SerialPortInfo mInfo; private final @NonNull ISerialManager mService; /** @hide */ @VisibleForTesting public SerialPort(@NonNull SerialPortInfo info, @NonNull ISerialManager service) { public SerialPort(@NonNull Context context, @NonNull SerialPortInfo info, @NonNull ISerialManager service) { mContext = context; mInfo = info; mService = service; } Loading Loading @@ -148,7 +149,7 @@ public final class SerialPort { Objects.requireNonNull(executor, "Executor must not be null"); Objects.requireNonNull(receiver, "Receiver must not be null"); try { mService.requestOpen(mInfo.getName(), flags, exclusive, mService.requestOpen(mInfo.getName(), flags, exclusive, mContext.getPackageName(), new SerialPortResponseCallback(executor, receiver)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -182,6 +183,7 @@ public final class SerialPort { return switch (errorCode) { case ErrorCode.ERROR_READING_DRIVERS -> new IOException(message); case ErrorCode.ERROR_PORT_NOT_FOUND -> new ErrnoException(message, ENOENT); case ErrorCode.ERROR_ACCESS_DENIED -> new SecurityException(message); case ErrorCode.ERROR_OPENING_PORT -> new ErrnoException(message, errno); default -> new IllegalStateException("Unexpected errorCode " + errorCode); }; Loading services/serial/java/com/android/server/serial/SerialManagerService.java +97 −29 Original line number Diff line number Diff line Loading @@ -28,21 +28,26 @@ import static com.android.server.serial.SerialConstants.DEV_DIR; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.hardware.serial.ISerialManager; import android.hardware.serial.ISerialPortListener; import android.hardware.serial.ISerialPortResponseCallback; import android.hardware.serial.ISerialPortResponseCallback.ErrorCode; import android.hardware.serial.SerialPortInfo; import android.os.Binder; import android.os.FileObserver; import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.Slog; import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; Loading @@ -68,18 +73,47 @@ public class SerialManagerService extends ISerialManager.Stub { @GuardedBy("mLock") private final HashMap<String, SerialPortInfo> mSerialPorts = new HashMap<>(); @GuardedBy("mLock") private boolean mIsStarted; private final Object mLock = new Object(); private final Context mContext; private final String[] mPortsInConfig; @GuardedBy("mLock") private final SparseArray<SerialUserAccessManager> mAccessManagerPerUser = new SparseArray<>(); private final RemoteCallbackList<ISerialPortListener> mListeners = new RemoteCallbackList<>(); private final SerialDriversDiscovery mSerialDriversDiscovery = new SerialDriversDiscovery(); private final SerialDevicesEnumerator mSerialDevicesEnumerator = new SerialDevicesEnumerator(); private SerialManagerService() {} @GuardedBy("mLock") private boolean mIsStarted; private SerialManagerService(Context context) { mContext = context; mPortsInConfig = stripDevPrefix(mContext.getResources().getStringArray(R.array.config_serialPorts)); } private static String[] stripDevPrefix(String[] portPaths) { if (portPaths.length == 0) { return portPaths; } final String devDirPrefix = DEV_DIR + "/"; ArrayList<String> portNames = new ArrayList<>(); for (int i = 0; i < portPaths.length; ++i) { String portPath = portPaths[i]; if (portPath.startsWith(devDirPrefix)) { portNames.add(portPath.substring(devDirPrefix.length())); } else { Slog.w(TAG, "Skipping port path not under /dev: " + portPath); } } return portNames.toArray(new String[0]); } @Override public List<SerialPortInfo> getSerialPorts() throws RemoteException { Loading Loading @@ -110,27 +144,56 @@ public class SerialManagerService extends ISerialManager.Stub { @Override public void requestOpen(@NonNull String portName, int flags, boolean exclusive, @NonNull ISerialPortResponseCallback callback) throws RemoteException { @NonNull String packageName, @NonNull ISerialPortResponseCallback callback) throws RemoteException { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final @UserIdInt int userId = UserHandle.getUserId(callingUid); synchronized (mLock) { try { startIfNeeded(); } catch (IOException e) { Slog.e(TAG, "Error reading the list of serial drivers", e); callback.onError(ErrorCode.ERROR_READING_DRIVERS, 0, e.getMessage()); deliverErrorToCallback( callback, ErrorCode.ERROR_READING_DRIVERS, /* errno */ 0, e.getMessage()); return; } SerialPortInfo port = mSerialPorts.get(portName); if (port == null) { try { callback.onError(ErrorCode.ERROR_PORT_NOT_FOUND, 0, portName); } catch (RemoteException e) { Slog.e(TAG, "Error sending error to callback", e); deliverErrorToCallback( callback, ErrorCode.ERROR_PORT_NOT_FOUND, /* errno */ 0, portName); return; } if (!mAccessManagerPerUser.contains(userId)) { mAccessManagerPerUser.put( userId, new SerialUserAccessManager(mContext, mPortsInConfig)); } final SerialUserAccessManager accessManager = mAccessManagerPerUser.get(userId); accessManager.requestAccess(portName, callingPid, callingUid, (resultPort, pid, uid, granted) -> { if (!granted) { deliverErrorToCallback( callback, ErrorCode.ERROR_ACCESS_DENIED, /* errno */ 0, "User denied " + packageName + " access to " + portName); return; } String path = DEV_DIR + "/" + portName; try { FileDescriptor fd = Os.open(path, toOsConstants(flags), /* mode= */ 0); deliverResultToCallback(callback, port, Os.open(path, toOsConstants(flags), /* mode */ 0)); } catch (ErrnoException e) { Slog.e(TAG, "Failed to open " + path, e); deliverErrorToCallback( callback, ErrorCode.ERROR_OPENING_PORT, e.errno, "open"); } }); } } private void deliverResultToCallback( @NonNull ISerialPortResponseCallback callback, SerialPortInfo port, FileDescriptor fd) { try (var pfd = new ParcelFileDescriptor(fd)) { callback.onResult(port, pfd); } catch (RemoteException | RuntimeException e) { Loading @@ -138,14 +201,14 @@ public class SerialManagerService extends ISerialManager.Stub { } catch (IOException e) { Slog.w(TAG, "Error closing the file descriptor", e); } } catch (ErrnoException e) { Slog.e(TAG, "Failed to open " + path, e); try { callback.onError(ErrorCode.ERROR_OPENING_PORT, e.errno, "open"); } catch (RemoteException e2) { Slog.e(TAG, "Error sending error to callback", e2); } } private void deliverErrorToCallback(@NonNull ISerialPortResponseCallback callback, @ErrorCode int errorCode, int errno, String message) { try { callback.onError(errorCode, errno, message); } catch (RemoteException e) { Slog.e(TAG, "Error sending error to callback", e); } } Loading Loading @@ -259,6 +322,9 @@ public class SerialManagerService extends ISerialManager.Stub { return; } } for (int i = mAccessManagerPerUser.size() - 1; i >= 0; --i) { mAccessManagerPerUser.valueAt(i).onPortRemoved(name); } Slog.d(TAG, "Removed serial device " + name); int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { Loading @@ -272,15 +338,17 @@ public class SerialManagerService extends ISerialManager.Stub { } public static class Lifecycle extends SystemService { private final Context mContext; public Lifecycle(@NonNull Context context) { super(context); mContext = context; } @Override public void onStart() { if (enableWiredSerialApi()) { publishBinderService(Context.SERIAL_SERVICE, new SerialManagerService()); publishBinderService(Context.SERIAL_SERVICE, new SerialManagerService(mContext)); } } } Loading Loading
core/java/android/hardware/serial/ISerialManager.aidl +7 −5 Original line number Diff line number Diff line Loading @@ -37,8 +37,10 @@ interface ISerialManager { * @param flags open flags {@code SerialPort.OPEN_FLAG_*} that define read/write mode and * other options. * @param exclusive whether the app needs exclusive access with TIOCEXCL(2const) * @param packageName the package name of the calling application * @param callback the receiver of the operation result. * @throws IllegalArgumentException if the set of flags is not correct. */ void requestOpen(in String portName, in int flags, in boolean exclusive, in ISerialPortResponseCallback callback); void requestOpen(in String portName, in int flags, in boolean exclusive, in String packageName, in ISerialPortResponseCallback callback); }
core/java/android/hardware/serial/ISerialPortResponseCallback.aidl +3 −1 Original line number Diff line number Diff line Loading @@ -32,8 +32,10 @@ oneway interface ISerialPortResponseCallback { ERROR_READING_DRIVERS = 0, // Serial port with the given name does not exist. ERROR_PORT_NOT_FOUND = 1, // SecurityException due to access denied. ERROR_ACCESS_DENIED = 2, // ErrnoException while opening the serial port. ERROR_OPENING_PORT = 2, ERROR_OPENING_PORT = 3, } /** Loading
core/java/android/hardware/serial/SerialManager.java +3 −4 Original line number Diff line number Diff line Loading @@ -41,7 +41,6 @@ import java.util.concurrent.Executor; public final class SerialManager { private static final String TAG = "SerialManager"; @SuppressWarnings("unused") private final @NonNull Context mContext; private final @NonNull ISerialManager mService; Loading @@ -68,7 +67,7 @@ public final class SerialManager { List<SerialPortInfo> infos = mService.getSerialPorts(); List<SerialPort> ports = new ArrayList<>(infos.size()); for (int i = 0; i < infos.size(); i++) { ports.add(new SerialPort(infos.get(i), mService)); ports.add(new SerialPort(mContext, infos.get(i), mService)); } return Collections.unmodifiableList(ports); } catch (RemoteException e) { Loading Loading @@ -131,7 +130,7 @@ public final class SerialManager { private class SerialPortServiceListener extends ISerialPortListener.Stub { @Override public void onSerialPortConnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); SerialPort port = new SerialPort(mContext, info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); Loading @@ -147,7 +146,7 @@ public final class SerialManager { @Override public void onSerialPortDisconnected(SerialPortInfo info) { SerialPort port = new SerialPort(info, mService); SerialPort port = new SerialPort(mContext, info, mService); synchronized (mLock) { for (Map.Entry<SerialPortListener, Executor> e : mListeners.entrySet()) { Executor executor = e.getValue(); Loading
core/java/android/hardware/serial/SerialPort.java +7 −5 Original line number Diff line number Diff line Loading @@ -23,13 +23,12 @@ import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.content.Context; import android.os.OutcomeReceiver; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.system.ErrnoException; import com.android.internal.annotations.VisibleForTesting; import java.io.IOException; import java.lang.annotation.Retention; import java.util.Objects; Loading Loading @@ -92,12 +91,14 @@ public final class SerialPort { */ public static final int OPEN_FLAG_SYNC = 1 << 20; private final @NonNull Context mContext; private final @NonNull SerialPortInfo mInfo; private final @NonNull ISerialManager mService; /** @hide */ @VisibleForTesting public SerialPort(@NonNull SerialPortInfo info, @NonNull ISerialManager service) { public SerialPort(@NonNull Context context, @NonNull SerialPortInfo info, @NonNull ISerialManager service) { mContext = context; mInfo = info; mService = service; } Loading Loading @@ -148,7 +149,7 @@ public final class SerialPort { Objects.requireNonNull(executor, "Executor must not be null"); Objects.requireNonNull(receiver, "Receiver must not be null"); try { mService.requestOpen(mInfo.getName(), flags, exclusive, mService.requestOpen(mInfo.getName(), flags, exclusive, mContext.getPackageName(), new SerialPortResponseCallback(executor, receiver)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); Loading Loading @@ -182,6 +183,7 @@ public final class SerialPort { return switch (errorCode) { case ErrorCode.ERROR_READING_DRIVERS -> new IOException(message); case ErrorCode.ERROR_PORT_NOT_FOUND -> new ErrnoException(message, ENOENT); case ErrorCode.ERROR_ACCESS_DENIED -> new SecurityException(message); case ErrorCode.ERROR_OPENING_PORT -> new ErrnoException(message, errno); default -> new IllegalStateException("Unexpected errorCode " + errorCode); }; Loading
services/serial/java/com/android/server/serial/SerialManagerService.java +97 −29 Original line number Diff line number Diff line Loading @@ -28,21 +28,26 @@ import static com.android.server.serial.SerialConstants.DEV_DIR; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.content.Context; import android.hardware.serial.ISerialManager; import android.hardware.serial.ISerialPortListener; import android.hardware.serial.ISerialPortResponseCallback; import android.hardware.serial.ISerialPortResponseCallback.ErrorCode; import android.hardware.serial.SerialPortInfo; import android.os.Binder; import android.os.FileObserver; import android.os.ParcelFileDescriptor; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.UserHandle; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.Slog; import android.util.SparseArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; Loading @@ -68,18 +73,47 @@ public class SerialManagerService extends ISerialManager.Stub { @GuardedBy("mLock") private final HashMap<String, SerialPortInfo> mSerialPorts = new HashMap<>(); @GuardedBy("mLock") private boolean mIsStarted; private final Object mLock = new Object(); private final Context mContext; private final String[] mPortsInConfig; @GuardedBy("mLock") private final SparseArray<SerialUserAccessManager> mAccessManagerPerUser = new SparseArray<>(); private final RemoteCallbackList<ISerialPortListener> mListeners = new RemoteCallbackList<>(); private final SerialDriversDiscovery mSerialDriversDiscovery = new SerialDriversDiscovery(); private final SerialDevicesEnumerator mSerialDevicesEnumerator = new SerialDevicesEnumerator(); private SerialManagerService() {} @GuardedBy("mLock") private boolean mIsStarted; private SerialManagerService(Context context) { mContext = context; mPortsInConfig = stripDevPrefix(mContext.getResources().getStringArray(R.array.config_serialPorts)); } private static String[] stripDevPrefix(String[] portPaths) { if (portPaths.length == 0) { return portPaths; } final String devDirPrefix = DEV_DIR + "/"; ArrayList<String> portNames = new ArrayList<>(); for (int i = 0; i < portPaths.length; ++i) { String portPath = portPaths[i]; if (portPath.startsWith(devDirPrefix)) { portNames.add(portPath.substring(devDirPrefix.length())); } else { Slog.w(TAG, "Skipping port path not under /dev: " + portPath); } } return portNames.toArray(new String[0]); } @Override public List<SerialPortInfo> getSerialPorts() throws RemoteException { Loading Loading @@ -110,27 +144,56 @@ public class SerialManagerService extends ISerialManager.Stub { @Override public void requestOpen(@NonNull String portName, int flags, boolean exclusive, @NonNull ISerialPortResponseCallback callback) throws RemoteException { @NonNull String packageName, @NonNull ISerialPortResponseCallback callback) throws RemoteException { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final @UserIdInt int userId = UserHandle.getUserId(callingUid); synchronized (mLock) { try { startIfNeeded(); } catch (IOException e) { Slog.e(TAG, "Error reading the list of serial drivers", e); callback.onError(ErrorCode.ERROR_READING_DRIVERS, 0, e.getMessage()); deliverErrorToCallback( callback, ErrorCode.ERROR_READING_DRIVERS, /* errno */ 0, e.getMessage()); return; } SerialPortInfo port = mSerialPorts.get(portName); if (port == null) { try { callback.onError(ErrorCode.ERROR_PORT_NOT_FOUND, 0, portName); } catch (RemoteException e) { Slog.e(TAG, "Error sending error to callback", e); deliverErrorToCallback( callback, ErrorCode.ERROR_PORT_NOT_FOUND, /* errno */ 0, portName); return; } if (!mAccessManagerPerUser.contains(userId)) { mAccessManagerPerUser.put( userId, new SerialUserAccessManager(mContext, mPortsInConfig)); } final SerialUserAccessManager accessManager = mAccessManagerPerUser.get(userId); accessManager.requestAccess(portName, callingPid, callingUid, (resultPort, pid, uid, granted) -> { if (!granted) { deliverErrorToCallback( callback, ErrorCode.ERROR_ACCESS_DENIED, /* errno */ 0, "User denied " + packageName + " access to " + portName); return; } String path = DEV_DIR + "/" + portName; try { FileDescriptor fd = Os.open(path, toOsConstants(flags), /* mode= */ 0); deliverResultToCallback(callback, port, Os.open(path, toOsConstants(flags), /* mode */ 0)); } catch (ErrnoException e) { Slog.e(TAG, "Failed to open " + path, e); deliverErrorToCallback( callback, ErrorCode.ERROR_OPENING_PORT, e.errno, "open"); } }); } } private void deliverResultToCallback( @NonNull ISerialPortResponseCallback callback, SerialPortInfo port, FileDescriptor fd) { try (var pfd = new ParcelFileDescriptor(fd)) { callback.onResult(port, pfd); } catch (RemoteException | RuntimeException e) { Loading @@ -138,14 +201,14 @@ public class SerialManagerService extends ISerialManager.Stub { } catch (IOException e) { Slog.w(TAG, "Error closing the file descriptor", e); } } catch (ErrnoException e) { Slog.e(TAG, "Failed to open " + path, e); try { callback.onError(ErrorCode.ERROR_OPENING_PORT, e.errno, "open"); } catch (RemoteException e2) { Slog.e(TAG, "Error sending error to callback", e2); } } private void deliverErrorToCallback(@NonNull ISerialPortResponseCallback callback, @ErrorCode int errorCode, int errno, String message) { try { callback.onError(errorCode, errno, message); } catch (RemoteException e) { Slog.e(TAG, "Error sending error to callback", e); } } Loading Loading @@ -259,6 +322,9 @@ public class SerialManagerService extends ISerialManager.Stub { return; } } for (int i = mAccessManagerPerUser.size() - 1; i >= 0; --i) { mAccessManagerPerUser.valueAt(i).onPortRemoved(name); } Slog.d(TAG, "Removed serial device " + name); int n = mListeners.beginBroadcast(); for (int i = 0; i < n; i++) { Loading @@ -272,15 +338,17 @@ public class SerialManagerService extends ISerialManager.Stub { } public static class Lifecycle extends SystemService { private final Context mContext; public Lifecycle(@NonNull Context context) { super(context); mContext = context; } @Override public void onStart() { if (enableWiredSerialApi()) { publishBinderService(Context.SERIAL_SERVICE, new SerialManagerService()); publishBinderService(Context.SERIAL_SERVICE, new SerialManagerService(mContext)); } } } Loading