Update shell open command to have a mode.

We need to open files for reading sometimes, so now
we can.

Test: manual

Change-Id: If089c1e7a4aac1d85784e070d2fccb04b9d84391
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 014c995..40dbbf5 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -61,7 +61,8 @@
 public:
     bool mActive = true;
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         String8 path8(path);
         char cwd[256];
         getcwd(cwd, 256);
@@ -71,7 +72,26 @@
             aerr << "Open attempt after active for: " << fullPath << endl;
             return -EPERM;
         }
-        int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
+        int flags = 0;
+        bool checkRead = false;
+        bool checkWrite = false;
+        if (mode == String16("w")) {
+            flags = O_WRONLY|O_CREAT|O_TRUNC;
+            checkWrite = true;
+        } else if (mode == String16("w+")) {
+            flags = O_RDWR|O_CREAT|O_TRUNC;
+            checkRead = checkWrite = true;
+        } else if (mode == String16("r")) {
+            flags = O_RDONLY;
+            checkRead = true;
+        } else if (mode == String16("r+")) {
+            flags = O_RDWR;
+            checkRead = checkWrite = true;
+        } else {
+            aerr << "Invalid mode requested: " << mode.string() << endl;
+            return -EINVAL;
+        }
+        int fd = open(fullPath.string(), flags, S_IRWXU|S_IRWXG);
         if (fd < 0) {
             return fd;
         }
@@ -80,14 +100,27 @@
             security_context_t tmp = NULL;
             int ret = getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
-            int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                    "file", "write", NULL);
-            if (accessGranted != 0) {
-                close(fd);
-                aerr << "System server has no access to file context " << context.get()
-                        << " (from path " << fullPath.string() << ", context "
-                        << seLinuxContext8.string() << ")" << endl;
-                return -EPERM;
+            if (checkWrite) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "write", NULL);
+                if (accessGranted != 0) {
+                    close(fd);
+                    aerr << "System server has no access to write file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
+            }
+            if (checkRead) {
+                int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
+                        "file", "read", NULL);
+                if (accessGranted != 0) {
+                    close(fd);
+                    aerr << "System server has no access to read file context " << context.get()
+                            << " (from path " << fullPath.string() << ", context "
+                            << seLinuxContext8.string() << ")" << endl;
+                    return -EPERM;
+                }
             }
         }
         return fd;
diff --git a/libs/binder/IShellCallback.cpp b/libs/binder/IShellCallback.cpp
index c793df3..23b83a6 100644
--- a/libs/binder/IShellCallback.cpp
+++ b/libs/binder/IShellCallback.cpp
@@ -39,11 +39,13 @@
     {
     }
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) {
         Parcel data, reply;
         data.writeInterfaceToken(IShellCallback::getInterfaceDescriptor());
         data.writeString16(path);
         data.writeString16(seLinuxContext);
+        data.writeString16(mode);
         remote()->transact(OP_OPEN_OUTPUT_FILE, data, &reply, 0);
         reply.readExceptionCode();
         int fd = reply.readParcelFileDescriptor();
@@ -64,7 +66,8 @@
             CHECK_INTERFACE(IShellCallback, data, reply);
             String16 path(data.readString16());
             String16 seLinuxContext(data.readString16());
-            int fd = openOutputFile(path, seLinuxContext);
+            String16 mode(data.readString16());
+            int fd = openFile(path, seLinuxContext, mode);
             if (reply != NULL) {
                 reply->writeNoException();
                 if (fd >= 0) {
diff --git a/libs/binder/include/binder/IShellCallback.h b/libs/binder/include/binder/IShellCallback.h
index fda9ee6..b47e995 100644
--- a/libs/binder/include/binder/IShellCallback.h
+++ b/libs/binder/include/binder/IShellCallback.h
@@ -29,7 +29,8 @@
 public:
     DECLARE_META_INTERFACE(ShellCallback);
 
-    virtual int openOutputFile(const String16& path, const String16& seLinuxContext) = 0;
+    virtual int openFile(const String16& path, const String16& seLinuxContext,
+            const String16& mode) = 0;
 
     enum {
         OP_OPEN_OUTPUT_FILE = IBinder::FIRST_CALL_TRANSACTION