From 823287d28ed75f96cee31cf465220fcbcbc5c7ac Mon Sep 17 00:00:00 2001
From: Badhri Jagan Sridharan
Date: Mon, 23 Jan 2017 17:13:15 -0800
Subject: [PATCH] Refactor UsbPortManager to use the binderised USB HAL
Move to a USB HAL to handle type-c ports as upstream is
considering in merging a generic type-c interface to mainline
kernel. However, the new sysfs interface can see minor changes
in the future as the sysfs interface is sitll going to land
in testing and it is still under review.
Bug: 31015010
Test: Manually tested on Angler and sailfish for type-c role switches.
Change-Id: I26771074c4b4f79a133e519bc6d35a4864a696d8
---
Android.mk | 1 +
core/java/android/hardware/usb/UsbPort.java | 69 ++-
services/usb/Android.mk | 2 +
.../android/server/usb/UsbPortManager.java | 551 ++++++++++--------
4 files changed, 349 insertions(+), 274 deletions(-)
diff --git a/Android.mk b/Android.mk
index 21bd76b76a62f..7be48e0c51742 100644
--- a/Android.mk
+++ b/Android.mk
@@ -535,6 +535,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
framework-protos \
android.hardware.thermal@1.0-java-constants \
android.hardware.health@1.0-java-constants \
+ android.hardware.usb@1.0-java-constants \
LOCAL_PROTOC_OPTIMIZE_TYPE := stream
LOCAL_PROTOC_FLAGS := \
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index c9a4e9b6015ab..fea730e492c88 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -16,11 +16,12 @@
package android.hardware.usb;
-import com.android.internal.util.Preconditions;
-
+import android.hardware.usb.V1_0.Constants;
import android.os.Parcel;
import android.os.Parcelable;
+import com.android.internal.util.Preconditions;
+
/**
* Represents a physical USB port and describes its characteristics.
*
@@ -33,6 +34,7 @@ public final class UsbPort implements Parcelable {
private final String mId;
private final int mSupportedModes;
+ public static final int MODE_NONE = Constants.PortMode.NONE;
/**
* Mode bit: This USB port can act as a downstream facing port (host).
*
@@ -40,7 +42,7 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
*
*/
- public static final int MODE_DFP = 1 << 0;
+ public static final int MODE_DFP = Constants.PortMode.DFP;
/**
* Mode bit: This USB port can act as an upstream facing port (device).
@@ -49,7 +51,7 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
*
*/
- public static final int MODE_UFP = 1 << 1;
+ public static final int MODE_UFP = Constants.PortMode.UFP;
/**
* Mode bit: This USB port can act either as an downstream facing port (host) or as
@@ -60,29 +62,43 @@ public final class UsbPort implements Parcelable {
* combination of roles (and possibly others as well).
*
*/
- public static final int MODE_DUAL = MODE_DFP | MODE_UFP;
+ public static final int MODE_DUAL = Constants.PortMode.DRP;
+
+ /**
+ * Power role: This USB port does not have a power role.
+ */
+ public static final int POWER_ROLE_NONE = Constants.PortPowerRole.NONE;
/**
* Power role: This USB port can act as a source (provide power).
*/
- public static final int POWER_ROLE_SOURCE = 1;
+ public static final int POWER_ROLE_SOURCE = Constants.PortPowerRole.SOURCE;
/**
* Power role: This USB port can act as a sink (receive power).
*/
- public static final int POWER_ROLE_SINK = 2;
+ public static final int POWER_ROLE_SINK = Constants.PortPowerRole.SINK;
+
+ /**
+ * Power role: This USB port does not have a data role.
+ */
+ public static final int DATA_ROLE_NONE = Constants.PortDataRole.NONE;
/**
* Data role: This USB port can act as a host (access data services).
*/
- public static final int DATA_ROLE_HOST = 1;
+ public static final int DATA_ROLE_HOST = Constants.PortDataRole.HOST;
/**
* Data role: This USB port can act as a device (offer data services).
*/
- public static final int DATA_ROLE_DEVICE = 2;
+ public static final int DATA_ROLE_DEVICE = Constants.PortDataRole.DEVICE;
- private static final int NUM_DATA_ROLES = 3;
+ private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
+ /**
+ * Points to the first power role in the IUsb HAL.
+ */
+ private static final int POWER_ROLE_OFFSET = Constants.PortPowerRole.NONE;
/** @hide */
public UsbPort(String id, int supportedModes) {
@@ -126,14 +142,14 @@ public final class UsbPort implements Parcelable {
*/
public static int combineRolesAsBit(int powerRole, int dataRole) {
checkRoles(powerRole, dataRole);
- final int index = powerRole * NUM_DATA_ROLES + dataRole;
+ final int index = ((powerRole - POWER_ROLE_OFFSET) * NUM_DATA_ROLES) + dataRole;
return 1 << index;
}
/** @hide */
public static String modeToString(int mode) {
switch (mode) {
- case 0:
+ case MODE_NONE:
return "none";
case MODE_DFP:
return "dfp";
@@ -149,7 +165,7 @@ public final class UsbPort implements Parcelable {
/** @hide */
public static String powerRoleToString(int role) {
switch (role) {
- case 0:
+ case POWER_ROLE_NONE:
return "no-power";
case POWER_ROLE_SOURCE:
return "source";
@@ -163,7 +179,7 @@ public final class UsbPort implements Parcelable {
/** @hide */
public static String dataRoleToString(int role) {
switch (role) {
- case 0:
+ case DATA_ROLE_NONE:
return "no-data";
case DATA_ROLE_HOST:
return "host";
@@ -183,7 +199,7 @@ public final class UsbPort implements Parcelable {
while (combo != 0) {
final int index = Integer.numberOfTrailingZeros(combo);
combo &= ~(1 << index);
- final int powerRole = index / NUM_DATA_ROLES;
+ final int powerRole = (index / NUM_DATA_ROLES + POWER_ROLE_OFFSET);
final int dataRole = index % NUM_DATA_ROLES;
if (first) {
first = false;
@@ -199,10 +215,29 @@ public final class UsbPort implements Parcelable {
return result.toString();
}
+ /** @hide */
+ public static void checkMode(int powerRole) {
+ Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
+ Constants.PortMode.NUM_MODES - 1, "portMode");
+ }
+
+ /** @hide */
+ public static void checkPowerRole(int dataRole) {
+ Preconditions.checkArgumentInRange(dataRole, Constants.PortPowerRole.NONE,
+ Constants.PortPowerRole.NUM_POWER_ROLES - 1, "powerRole");
+ }
+
+ /** @hide */
+ public static void checkDataRole(int mode) {
+ Preconditions.checkArgumentInRange(mode, Constants.PortDataRole.NONE,
+ Constants.PortDataRole.NUM_DATA_ROLES - 1, "powerRole");
+ }
+
/** @hide */
public static void checkRoles(int powerRole, int dataRole) {
- Preconditions.checkArgumentInRange(powerRole, 0, POWER_ROLE_SINK, "powerRole");
- Preconditions.checkArgumentInRange(dataRole, 0, DATA_ROLE_DEVICE, "dataRole");
+ Preconditions.checkArgumentInRange(powerRole, POWER_ROLE_NONE, POWER_ROLE_SINK,
+ "powerRole");
+ Preconditions.checkArgumentInRange(dataRole, DATA_ROLE_NONE, DATA_ROLE_DEVICE, "dataRole");
}
@Override
diff --git a/services/usb/Android.mk b/services/usb/Android.mk
index feabf0a970c24..f560e71ebe6a7 100644
--- a/services/usb/Android.mk
+++ b/services/usb/Android.mk
@@ -8,5 +8,7 @@ LOCAL_SRC_FILES += \
$(call all-java-files-under,java)
LOCAL_JAVA_LIBRARIES := services.core
+LOCAL_STATIC_JAVA_LIBRARIES := android.hardware.usb@1.0-java-static \
+android.hidl.manager@1.0-java-static
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 4aff3d54834a9..4b8e4c8ab13a8 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -16,36 +16,40 @@
package com.android.server.usb;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.FgThread;
-
import android.content.Context;
import android.content.Intent;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.hardware.usb.V1_0.IUsb;
+import android.hardware.usb.V1_0.IUsbCallback;
+import android.hardware.usb.V1_0.PortRole;
+import android.hardware.usb.V1_0.PortRoleType;
+import android.hardware.usb.V1_0.PortStatus;
+import android.hardware.usb.V1_0.Status;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.HwBinder;
import android.os.Message;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.os.UEventObserver;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
import android.os.UserHandle;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Slog;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.FgThread;
-import libcore.io.IoUtils;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
/**
* Allows trusted components to control the properties of physical USB ports
- * via the "/sys/class/dual_role_usb" kernel interface.
+ * via the IUsb.hal.
*
* Note: This interface may not be supported on all chipsets since the USB drivers
* must be changed to publish this information through the module. At the moment
@@ -60,43 +64,6 @@ public class UsbPortManager {
private static final int MSG_UPDATE_PORTS = 1;
- // UEvent path to watch.
- private static final String UEVENT_FILTER = "SUBSYSTEM=dual_role_usb";
-
- // SysFS directory that contains USB ports as subdirectories.
- private static final String SYSFS_CLASS = "/sys/class/dual_role_usb";
-
- // SysFS file that contains a USB port's supported modes. (read-only)
- // Contents: "", "ufp", "dfp", or "ufp dfp".
- private static final String SYSFS_PORT_SUPPORTED_MODES = "supported_modes";
-
- // SysFS file that contains a USB port's current mode. (read-write if configurable)
- // Contents: "", "ufp", or "dfp".
- private static final String SYSFS_PORT_MODE = "mode";
-
- // SysFS file that contains a USB port's current power role. (read-write if configurable)
- // Contents: "", "source", or "sink".
- private static final String SYSFS_PORT_POWER_ROLE = "power_role";
-
- // SysFS file that contains a USB port's current data role. (read-write if configurable)
- // Contents: "", "host", or "device".
- private static final String SYSFS_PORT_DATA_ROLE = "data_role";
-
- // Port modes: upstream facing port or downstream facing port.
- private static final String PORT_MODE_DFP = "dfp";
- private static final String PORT_MODE_UFP = "ufp";
-
- // Port power roles: source or sink.
- private static final String PORT_POWER_ROLE_SOURCE = "source";
- private static final String PORT_POWER_ROLE_SINK = "sink";
-
- // Port data roles: host or device.
- private static final String PORT_DATA_ROLE_HOST = "host";
- private static final String PORT_DATA_ROLE_DEVICE = "device";
-
- private static final String USB_TYPEC_PROP_PREFIX = "sys.usb.typec.";
- private static final String USB_TYPEC_STATE = "sys.usb.typec.state";
-
// All non-trivial role combinations.
private static final int COMBO_SOURCE_HOST =
UsbPort.combineRolesAsBit(UsbPort.POWER_ROLE_SOURCE, UsbPort.DATA_ROLE_HOST);
@@ -110,8 +77,29 @@ public class UsbPortManager {
// The system context.
private final Context mContext;
- // True if we have kernel support.
- private final boolean mHaveKernelSupport;
+ // Proxy object for the usb hal daemon.
+ // @GuardedBy("mLock")
+ private IUsb mProxy = null;
+
+ // Callback when the UsbPort status is changed by the kernel.
+ // Mostly due a command sent by the remote Usb device.
+ private HALCallback mHALCallback = new HALCallback(null, this);
+
+ // Notification object used to listen to the start of the usb daemon.
+ private final ServiceNotification mServiceNotification = new ServiceNotification();
+
+ // Cookie sent for usb hal death notification.
+ private static final int USB_HAL_DEATH_COOKIE = 1000;
+
+ // Usb hal service name.
+ private static String sSERVICENAME = "usb_hal";
+
+ // Used as the key while sending the bundle to Main thread.
+ private static final String PORT_INFO = "port_info";
+
+ // This is monitored to prevent updating the protInfo before the system
+ // is ready.
+ private boolean mSystemReady;
// Mutex for all mutable shared state.
private final Object mLock = new Object();
@@ -123,17 +111,37 @@ public class UsbPortManager {
private final ArrayMap mPorts = new ArrayMap();
// List of all simulated ports, indexed by id.
- private final ArrayMap mSimulatedPorts =
- new ArrayMap();
+ private final ArrayMap mSimulatedPorts =
+ new ArrayMap();
public UsbPortManager(Context context) {
mContext = context;
- mHaveKernelSupport = new File(SYSFS_CLASS).exists();
+ try {
+ boolean ret = IServiceManager.getService("manager")
+ .registerForNotifications("android.hardware.usb@1.0::IUsb",
+ "", mServiceNotification);
+ if (!ret) {
+ logAndPrint(Log.ERROR, null, "Failed to register service start notification");
+ }
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, null, "Failed to register service start notification");
+ Thread.dumpStack();
+ return;
+ }
+ connectToProxy(null);
}
public void systemReady() {
- mUEventObserver.startObserving(UEVENT_FILTER);
- scheduleUpdatePorts();
+ if (mProxy != null) {
+ try {
+ mProxy.queryPortStatus();
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, null,
+ "ServiceStart: Failed to query port status");
+ Thread.dumpStack();
+ }
+ }
+ mSystemReady = true;
}
public UsbPort[] getPorts() {
@@ -223,20 +231,14 @@ public class UsbPortManager {
+ ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole)
+ ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
- SimulatedPortInfo sim = mSimulatedPorts.get(portId);
+ RawPortInfo sim = mSimulatedPorts.get(portId);
if (sim != null) {
// Change simulated state.
sim.mCurrentMode = newMode;
sim.mCurrentPowerRole = newPowerRole;
sim.mCurrentDataRole = newDataRole;
- } else if (mHaveKernelSupport) {
- // Change actual state.
- final File portDir = new File(SYSFS_CLASS, portId);
- if (!portDir.exists()) {
- logAndPrint(Log.ERROR, pw, "USB port not found: portId=" + portId);
- return;
- }
-
+ updatePortsLocked(pw, null);
+ } else if (mProxy != null) {
if (currentMode != newMode) {
// Changing the mode will have the side-effect of also changing
// the power and data roles but it might take some time to apply
@@ -244,38 +246,54 @@ public class UsbPortManager {
// hardware, we have no way of knowing whether it will work apriori
// which is why we would prefer to set the power and data roles
// directly instead.
- if (!writeFile(portDir, SYSFS_PORT_MODE,
- newMode == UsbPort.MODE_DFP ? PORT_MODE_DFP : PORT_MODE_UFP)) {
- logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: "
+
+ logAndPrint(Log.ERROR, pw, "Trying to set the USB port mode: "
+ "portId=" + portId
+ ", newMode=" + UsbPort.modeToString(newMode));
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.MODE;
+ newRole.role = newMode;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, pw, "Failed to set the USB port mode: "
+ + "portId=" + portId
+ + ", newMode=" + UsbPort.modeToString(newRole.role));
+ Thread.dumpStack();
return;
}
} else {
// Change power and data role independently as needed.
if (currentPowerRole != newPowerRole) {
- if (!writeFile(portDir, SYSFS_PORT_POWER_ROLE,
- newPowerRole == UsbPort.POWER_ROLE_SOURCE
- ? PORT_POWER_ROLE_SOURCE : PORT_POWER_ROLE_SINK)) {
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.POWER_ROLE;
+ newRole.role = newPowerRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
logAndPrint(Log.ERROR, pw, "Failed to set the USB port power role: "
+ "portId=" + portId
- + ", newPowerRole=" + UsbPort.powerRoleToString(newPowerRole));
+ + ", newPowerRole=" + UsbPort.powerRoleToString(newRole.role));
+ Thread.dumpStack();
return;
}
}
if (currentDataRole != newDataRole) {
- if (!writeFile(portDir, SYSFS_PORT_DATA_ROLE,
- newDataRole == UsbPort.DATA_ROLE_HOST
- ? PORT_DATA_ROLE_HOST : PORT_DATA_ROLE_DEVICE)) {
+ PortRole newRole = new PortRole();
+ newRole.type = PortRoleType.DATA_ROLE;
+ newRole.role = newDataRole;
+ try {
+ mProxy.switchRole(portId, newRole);
+ } catch (RemoteException e) {
logAndPrint(Log.ERROR, pw, "Failed to set the USB port data role: "
+ "portId=" + portId
- + ", newDataRole=" + UsbPort.dataRoleToString(newDataRole));
+ + ", newDataRole=" + UsbPort.dataRoleToString(newRole.role));
+ Thread.dumpStack();
return;
}
}
}
}
- updatePortsLocked(pw);
}
}
@@ -289,8 +307,8 @@ public class UsbPortManager {
pw.println("Adding simulated port: portId=" + portId
+ ", supportedModes=" + UsbPort.modeToString(supportedModes));
mSimulatedPorts.put(portId,
- new SimulatedPortInfo(portId, supportedModes));
- updatePortsLocked(pw);
+ new RawPortInfo(portId, supportedModes));
+ updatePortsLocked(pw, null);
}
}
@@ -298,7 +316,7 @@ public class UsbPortManager {
int powerRole, boolean canChangePowerRole,
int dataRole, boolean canChangeDataRole, IndentingPrintWriter pw) {
synchronized (mLock) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ final RawPortInfo portInfo = mSimulatedPorts.get(portId);
if (portInfo == null) {
pw.println("Cannot connect simulated port which does not exist.");
return;
@@ -328,13 +346,13 @@ public class UsbPortManager {
portInfo.mCanChangePowerRole = canChangePowerRole;
portInfo.mCurrentDataRole = dataRole;
portInfo.mCanChangeDataRole = canChangeDataRole;
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
synchronized (mLock) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.get(portId);
+ final RawPortInfo portInfo = mSimulatedPorts.get(portId);
if (portInfo == null) {
pw.println("Cannot disconnect simulated port which does not exist.");
return;
@@ -347,7 +365,7 @@ public class UsbPortManager {
portInfo.mCanChangePowerRole = false;
portInfo.mCurrentDataRole = 0;
portInfo.mCanChangeDataRole = false;
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
@@ -361,7 +379,7 @@ public class UsbPortManager {
pw.println("Disconnecting simulated port: portId=" + portId);
mSimulatedPorts.removeAt(index);
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
@@ -370,7 +388,7 @@ public class UsbPortManager {
pw.println("Removing all simulated ports and ending simulation.");
if (!mSimulatedPorts.isEmpty()) {
mSimulatedPorts.clear();
- updatePortsLocked(pw);
+ updatePortsLocked(pw, null);
}
}
}
@@ -393,9 +411,108 @@ public class UsbPortManager {
}
}
- private void updatePortsLocked(IndentingPrintWriter pw) {
- // Assume all ports are gone unless informed otherwise.
- // Kind of pessimistic but simple.
+ private static class HALCallback extends IUsbCallback.Stub {
+ public IndentingPrintWriter pw;
+ public UsbPortManager portManager;
+
+ HALCallback() {
+ super();
+ }
+
+ HALCallback(IndentingPrintWriter pw, UsbPortManager portManager) {
+ this.pw = pw;
+ this.portManager = portManager;
+ }
+
+ public void notifyPortStatusChange(ArrayList currentPortStatus, int retval) {
+ if (!portManager.mSystemReady) return;
+
+ if (retval != Status.SUCCESS) {
+ logAndPrint(Log.ERROR, pw, "port status enquiry failed");
+ return;
+ }
+
+ ArrayList newPortInfo = new ArrayList();
+
+ for (PortStatus current : currentPortStatus) {
+ RawPortInfo temp = new RawPortInfo(current.portName,
+ current.supportedModes, current.currentMode,
+ current.canChangeMode, current.currentPowerRole,
+ current.canChangePowerRole,
+ current.currentDataRole, current.canChangeDataRole);
+ newPortInfo.add(temp);
+ logAndPrint(Log.INFO, pw, "ClientCallback: " + current.portName);
+ }
+
+ Message message = portManager.mHandler.obtainMessage();
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(PORT_INFO, newPortInfo);
+ message.what = MSG_UPDATE_PORTS;
+ message.setData(bundle);
+ portManager.mHandler.sendMessage(message);
+ return;
+ }
+
+ public void notifyRoleSwitchStatus(String portName, PortRole role, int retval) {
+ if (retval == Status.SUCCESS) {
+ logAndPrint(Log.INFO, pw, portName + "role switch successful");
+ } else {
+ logAndPrint(Log.ERROR, pw, portName + "role switch failed");
+ }
+ }
+ };
+
+ final class DeathRecipient implements HwBinder.DeathRecipient {
+ public IndentingPrintWriter pw;
+
+ DeathRecipient(IndentingPrintWriter pw) {
+ this.pw = pw;
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_HAL_DEATH_COOKIE) {
+ logAndPrint(Log.ERROR, pw, "Usb hal service died cookie: " + cookie);
+ synchronized (mLock) {
+ mProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ logAndPrint(Log.INFO, null, "Usb hal service started " + fqName + " " + name);
+ connectToProxy(null);
+ }
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mLock) {
+ if (mProxy != null) return;
+
+ try {
+ mProxy = IUsb.getService(sSERVICENAME);
+ mProxy.linkToDeath(new DeathRecipient(pw), USB_HAL_DEATH_COOKIE);
+ mProxy.setCallback(mHALCallback);
+ mProxy.queryPortStatus();
+ } catch (NoSuchElementException e) {
+ logAndPrint(Log.ERROR, pw, sSERVICENAME + "not found."
+ + " Did the service failed to start ?");
+ Thread.dumpStack();
+ } catch (RemoteException e) {
+ logAndPrint(Log.ERROR, pw, sSERVICENAME + "connectToProxy: Service not responding");
+ Thread.dumpStack();
+ }
+ }
+ }
+
+ /**
+ * Simulated ports directly add the new roles to mSimulatedPorts before calling.
+ * USB hal callback populates and sends the newPortInfo.
+ */
+ private void updatePortsLocked(IndentingPrintWriter pw, ArrayList newPortInfo) {
for (int i = mPorts.size(); i-- > 0; ) {
mPorts.valueAt(i).mDisposition = PortInfo.DISPOSITION_REMOVED;
}
@@ -404,34 +521,18 @@ public class UsbPortManager {
if (!mSimulatedPorts.isEmpty()) {
final int count = mSimulatedPorts.size();
for (int i = 0; i < count; i++) {
- final SimulatedPortInfo portInfo = mSimulatedPorts.valueAt(i);
+ final RawPortInfo portInfo = mSimulatedPorts.valueAt(i);
addOrUpdatePortLocked(portInfo.mPortId, portInfo.mSupportedModes,
portInfo.mCurrentMode, portInfo.mCanChangeMode,
portInfo.mCurrentPowerRole, portInfo.mCanChangePowerRole,
portInfo.mCurrentDataRole, portInfo.mCanChangeDataRole, pw);
}
- } else if (mHaveKernelSupport) {
- final File[] portDirs = new File(SYSFS_CLASS).listFiles();
- if (portDirs != null) {
- for (File portDir : portDirs) {
- if (!portDir.isDirectory()) {
- continue;
- }
-
- // Parse the sysfs file contents.
- final String portId = portDir.getName();
- final int supportedModes = readSupportedModes(portDir);
- final int currentMode = readCurrentMode(portDir);
- final boolean canChangeMode = canChangeMode(portDir);
- final int currentPowerRole = readCurrentPowerRole(portDir);
- final boolean canChangePowerRole = canChangePowerRole(portDir);
- final int currentDataRole = readCurrentDataRole(portDir);
- final boolean canChangeDataRole = canChangeDataRole(portDir);
- addOrUpdatePortLocked(portId, supportedModes,
- currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole, pw);
- }
+ } else {
+ for (RawPortInfo currentPortInfo : newPortInfo) {
+ addOrUpdatePortLocked(currentPortInfo.mPortId, currentPortInfo.mSupportedModes,
+ currentPortInfo.mCurrentMode, currentPortInfo.mCanChangeMode,
+ currentPortInfo.mCurrentPowerRole, currentPortInfo.mCanChangePowerRole,
+ currentPortInfo.mCurrentDataRole, currentPortInfo.mCanChangeDataRole, pw);
}
}
@@ -457,20 +558,21 @@ public class UsbPortManager {
}
}
+
// Must only be called by updatePortsLocked.
private void addOrUpdatePortLocked(String portId, int supportedModes,
- int currentMode, boolean canChangeMode,
- int currentPowerRole, boolean canChangePowerRole,
- int currentDataRole, boolean canChangeDataRole,
- IndentingPrintWriter pw) {
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole,
+ IndentingPrintWriter pw) {
// Only allow mode switch capability for dual role ports.
// Validate that the current mode matches the supported modes we expect.
if (supportedModes != UsbPort.MODE_DUAL) {
canChangeMode = false;
if (currentMode != 0 && currentMode != supportedModes) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent current mode from USB "
- + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes)
- + ", currentMode=" + UsbPort.modeToString(currentMode));
+ + "port driver: supportedModes=" + UsbPort.modeToString(supportedModes)
+ + ", currentMode=" + UsbPort.modeToString(currentMode));
currentMode = 0;
}
}
@@ -485,8 +587,8 @@ public class UsbPortManager {
// Can change both power and data role independently.
// Assume all combinations are possible.
supportedRoleCombinations |=
- COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE
- | COMBO_SINK_HOST | COMBO_SINK_DEVICE;
+ COMBO_SOURCE_HOST | COMBO_SOURCE_DEVICE
+ | COMBO_SINK_HOST | COMBO_SINK_DEVICE;
} else if (canChangePowerRole) {
// Can only change power role.
// Assume data role must remain at its current value.
@@ -514,24 +616,24 @@ public class UsbPortManager {
if (portInfo == null) {
portInfo = new PortInfo(portId, supportedModes);
portInfo.setStatus(currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole,
- supportedRoleCombinations);
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations);
mPorts.put(portId, portInfo);
} else {
// Sanity check that ports aren't changing definition out from under us.
if (supportedModes != portInfo.mUsbPort.getSupportedModes()) {
logAndPrint(Log.WARN, pw, "Ignoring inconsistent list of supported modes from "
- + "USB port driver (should be immutable): "
- + "previous=" + UsbPort.modeToString(
- portInfo.mUsbPort.getSupportedModes())
- + ", current=" + UsbPort.modeToString(supportedModes));
+ + "USB port driver (should be immutable): "
+ + "previous=" + UsbPort.modeToString(
+ portInfo.mUsbPort.getSupportedModes())
+ + ", current=" + UsbPort.modeToString(supportedModes));
}
if (portInfo.setStatus(currentMode, canChangeMode,
- currentPowerRole, canChangePowerRole,
- currentDataRole, canChangeDataRole,
- supportedRoleCombinations)) {
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole,
+ supportedRoleCombinations)) {
portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
} else {
portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -572,120 +674,6 @@ public class UsbPortManager {
});
}
- private void scheduleUpdatePorts() {
- if (!mHandler.hasMessages(MSG_UPDATE_PORTS)) {
- mHandler.sendEmptyMessage(MSG_UPDATE_PORTS);
- }
- }
-
- private static int readSupportedModes(File portDir) {
- int modes = 0;
- final String contents = readFile(portDir, SYSFS_PORT_SUPPORTED_MODES);
- if (contents != null) {
- if (contents.contains(PORT_MODE_DFP)) {
- modes |= UsbPort.MODE_DFP;
- }
- if (contents.contains(PORT_MODE_UFP)) {
- modes |= UsbPort.MODE_UFP;
- }
- }
- return modes;
- }
-
- private static int readCurrentMode(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_MODE);
- if (contents != null) {
- if (contents.equals(PORT_MODE_DFP)) {
- return UsbPort.MODE_DFP;
- }
- if (contents.equals(PORT_MODE_UFP)) {
- return UsbPort.MODE_UFP;
- }
- }
- return 0;
- }
-
- private static int readCurrentPowerRole(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_POWER_ROLE);
- if (contents != null) {
- if (contents.equals(PORT_POWER_ROLE_SOURCE)) {
- return UsbPort.POWER_ROLE_SOURCE;
- }
- if (contents.equals(PORT_POWER_ROLE_SINK)) {
- return UsbPort.POWER_ROLE_SINK;
- }
- }
- return 0;
- }
-
- private static int readCurrentDataRole(File portDir) {
- final String contents = readFile(portDir, SYSFS_PORT_DATA_ROLE);
- if (contents != null) {
- if (contents.equals(PORT_DATA_ROLE_HOST)) {
- return UsbPort.DATA_ROLE_HOST;
- }
- if (contents.equals(PORT_DATA_ROLE_DEVICE)) {
- return UsbPort.DATA_ROLE_DEVICE;
- }
- }
- return 0;
- }
-
- private static boolean fileIsRootWritable(String path) {
- try {
- // If the file is user writable, then it is root writable.
- return (Os.stat(path).st_mode & OsConstants.S_IWUSR) != 0;
- } catch (ErrnoException e) {
- return false;
- }
- }
-
- private static boolean canChangeMode(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_MODE).getPath());
- }
-
- private static boolean canChangePowerRole(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_POWER_ROLE).getPath());
- }
-
- private static boolean canChangeDataRole(File portDir) {
- return fileIsRootWritable(new File(portDir, SYSFS_PORT_DATA_ROLE).getPath());
- }
-
- private static String readFile(File dir, String filename) {
- final File file = new File(dir, filename);
- try {
- return IoUtils.readFileAsString(file.getAbsolutePath()).trim();
- } catch (IOException ex) {
- return null;
- }
- }
-
- private static boolean waitForState(String property, String state) {
- // wait for the transition to complete.
- // give up after 5 seconds.
- // 5 seconds is probably too long, but we have seen hardware that takes
- // over 3 seconds to change states.
- String value = null;
- for (int i = 0; i < 100; i++) {
- // State transition is done when property is set to the new configuration
- value = SystemProperties.get(property);
- if (state.equals(value)) return true;
- SystemClock.sleep(50);
- }
- Slog.e(TAG, "waitForState(" + state + ") for " + property + " FAILED: got " + value);
- return false;
- }
-
- private static String propertyFromFilename(String filename) {
- return USB_TYPEC_PROP_PREFIX + filename;
- }
-
- private static boolean writeFile(File dir, String filename, String contents) {
- SystemProperties.set(propertyFromFilename(filename), contents);
- return waitForState(USB_TYPEC_STATE, contents);
- }
-
private static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
Slog.println(priority, TAG, msg);
if (pw != null) {
@@ -698,8 +686,10 @@ public class UsbPortManager {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_PORTS: {
+ Bundle b = msg.getData();
+ ArrayList PortInfo = b.getParcelableArrayList(PORT_INFO);
synchronized (mLock) {
- updatePortsLocked(null);
+ updatePortsLocked(null, PortInfo);
}
break;
}
@@ -707,13 +697,6 @@ public class UsbPortManager {
}
};
- private final UEventObserver mUEventObserver = new UEventObserver() {
- @Override
- public void onUEvent(UEvent event) {
- scheduleUpdatePorts();
- }
- };
-
/**
* Describes a USB port.
*/
@@ -764,10 +747,10 @@ public class UsbPortManager {
}
/**
- * Describes a simulated USB port.
- * Roughly mirrors the information we would ordinarily get from the kernel.
+ * Used for storing the raw data from the kernel
+ * Values of the member variables mocked directly incase of emulation.
*/
- private static final class SimulatedPortInfo {
+ private static final class RawPortInfo implements Parcelable {
public final String mPortId;
public final int mSupportedModes;
public int mCurrentMode;
@@ -777,9 +760,63 @@ public class UsbPortManager {
public int mCurrentDataRole;
public boolean mCanChangeDataRole;
- public SimulatedPortInfo(String portId, int supportedModes) {
+ RawPortInfo(String portId, int supportedModes) {
mPortId = portId;
mSupportedModes = supportedModes;
}
+
+ RawPortInfo(String portId, int supportedModes,
+ int currentMode, boolean canChangeMode,
+ int currentPowerRole, boolean canChangePowerRole,
+ int currentDataRole, boolean canChangeDataRole) {
+ mPortId = portId;
+ mSupportedModes = supportedModes;
+ mCurrentMode = currentMode;
+ mCanChangeMode = canChangeMode;
+ mCurrentPowerRole = currentPowerRole;
+ mCanChangePowerRole = canChangePowerRole;
+ mCurrentDataRole = currentDataRole;
+ mCanChangeDataRole = canChangeDataRole;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mPortId);
+ dest.writeInt(mSupportedModes);
+ dest.writeInt(mCurrentMode);
+ dest.writeByte((byte) (mCanChangeMode ? 1 : 0));
+ dest.writeInt(mCurrentPowerRole);
+ dest.writeByte((byte) (mCanChangePowerRole ? 1 : 0));
+ dest.writeInt(mCurrentDataRole);
+ dest.writeByte((byte) (mCanChangeDataRole ? 1 : 0));
+ }
+
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ @Override
+ public RawPortInfo createFromParcel(Parcel in) {
+ String id = in.readString();
+ int supportedModes = in.readInt();
+ int currentMode = in.readInt();
+ boolean canChangeMode = in.readByte() != 0;
+ int currentPowerRole = in.readInt();
+ boolean canChangePowerRole = in.readByte() != 0;
+ int currentDataRole = in.readInt();
+ boolean canChangeDataRole = in.readByte() != 0;
+ return new RawPortInfo(id, supportedModes, currentMode, canChangeMode,
+ currentPowerRole, canChangePowerRole,
+ currentDataRole, canChangeDataRole);
+ }
+
+ @Override
+ public RawPortInfo[] newArray(int size) {
+ return new RawPortInfo[size];
+ }
+ };
}
}