Use init to write usb typec props.

The sysfs nodes are owned by root, so we must use init to write to
them.

Bug: 21615151
Change-Id: Ia8c838827ff45794aa359443117ac85764cf3772
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index 52abcfe..7f182a4 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -26,8 +26,13 @@
 import android.hardware.usb.UsbPortStatus;
 import android.os.Handler;
 import android.os.Message;
+import android.os.SystemClock;
+import android.os.SystemProperties;
 import android.os.UEventObserver;
 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;
@@ -89,6 +94,9 @@
     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);
@@ -621,16 +629,25 @@
         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 new File(portDir, SYSFS_PORT_MODE).canWrite();
+        return fileIsRootWritable(new File(portDir, SYSFS_PORT_MODE).getPath());
     }
 
     private static boolean canChangePowerRole(File portDir) {
-        return new File(portDir, SYSFS_PORT_POWER_ROLE).canWrite();
+        return fileIsRootWritable(new File(portDir, SYSFS_PORT_POWER_ROLE).getPath());
     }
 
     private static boolean canChangeDataRole(File portDir) {
-        return new File(portDir, SYSFS_PORT_DATA_ROLE).canWrite();
+        return fileIsRootWritable(new File(portDir, SYSFS_PORT_DATA_ROLE).getPath());
     }
 
     private static String readFile(File dir, String filename) {
@@ -642,16 +659,29 @@
         }
     }
 
-    private static boolean writeFile(File dir, String filename, String contents) {
-        final File file = new File(dir, filename);
-        try {
-            try (FileWriter writer = new FileWriter(file)) {
-                writer.write(contents);
-            }
-            return true;
-        } catch (IOException ex) {
-            return false;
+    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) {