Merge "Update SELinux JNI to use helpers"
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index b12fdfc..0a97f39 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -23,428 +23,407 @@
 #include "selinux/selinux.h"
 #include "selinux/android.h"
 #include <errno.h>
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+#include <UniquePtr.h>
 
 namespace android {
 
-  static jboolean isSELinuxDisabled = true;
+struct SecurityContext_Delete {
+    void operator()(security_context_t p) const {
+        freecon(p);
+    }
+};
+typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
 
-  static void throw_NullPointerException(JNIEnv *env, const char* msg) {
-    jclass clazz;
-    clazz = env->FindClass("java/lang/NullPointerException");
-    env->ThrowNew(clazz, msg);
-  }
+static jboolean isSELinuxDisabled = true;
 
-  /*
-   * Function: isSELinuxEnabled
-   * Purpose:  checks whether SELinux is enabled/disbaled
-   * Parameters: none
-   * Return value : true (enabled) or false (disabled)
-   * Exceptions: none
-   */
-  static jboolean isSELinuxEnabled(JNIEnv *env, jobject classz) {
-
+/*
+ * Function: isSELinuxEnabled
+ * Purpose:  checks whether SELinux is enabled/disbaled
+ * Parameters: none
+ * Return value : true (enabled) or false (disabled)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
     return !isSELinuxDisabled;
-  }
+}
 
-  /*
-   * Function: isSELinuxEnforced
-   * Purpose: return the current SELinux enforce mode
-   * Parameters: none
-   * Return value: true (enforcing) or false (permissive)
-   * Exceptions: none
-   */
-  static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) {
+/*
+ * Function: isSELinuxEnforced
+ * Purpose: return the current SELinux enforce mode
+ * Parameters: none
+ * Return value: true (enforcing) or false (permissive)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
     return (security_getenforce() == 1) ? true : false;
-  }
+}
 
-  /*
-   * Function: setSELinuxEnforce
-   * Purpose: set the SE Linux enforcing mode
-   * Parameters: true (enforcing) or false (permissive)
-   * Return value: true (success) or false (fail)
-   * Exceptions: none
-   */
-  static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: setSELinuxEnforce
+ * Purpose: set the SE Linux enforcing mode
+ * Parameters: true (enforcing) or false (permissive)
+ * Return value: true (success) or false (fail)
+ * Exceptions: none
+ */
+static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    int enforce = (value) ? 1 : 0;
+    int enforce = value ? 1 : 0;
 
     return (security_setenforce(enforce) != -1) ? true : false;
-  }
+}
 
-  /*
-   * Function: getPeerCon
-   * Purpose: retrieves security context of peer socket
-   * Parameters:
-   *        fileDescriptor: peer socket file as a FileDescriptor object
-   * Returns: jstring representing the security_context of socket or NULL if error
-   * Exceptions: NullPointerException if fileDescriptor object is NULL
-   */
-  static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getPeerCon
+ * Purpose: retrieves security context of peer socket
+ * Parameters:
+ *        fileDescriptor: peer socket file as a FileDescriptor object
+ * Returns: jstring representing the security_context of socket or NULL if error
+ * Exceptions: NullPointerException if fileDescriptor object is NULL
+ */
+static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
     if (fileDescriptor == NULL) {
-      throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
-      return NULL;
+        jniThrowNullPointerException(env,
+                "Trying to check security context of a null peer socket.");
+        return NULL;
     }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
-
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
     if (env->ExceptionOccurred() != NULL) {
-      ALOGE("There was an issue with retrieving the file descriptor");
-      goto bail;
+        ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
+        return NULL;
     }
 
-    if (getpeercon(fd, &context) == -1)
-      goto bail;
+    security_context_t tmp;
+    int ret = getpeercon(fd, &tmp);
+    Unique_SecurityContext context(tmp);
 
-    ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);
-
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: setFSCreateCon
-   * Purpose: set security context used for creating a new file system object
-   * Parameters:
-   *       context: security_context_t representing the new context of a file system object,
-   *                set to NULL to return to the default policy behavior
-   * Returns: true on success, false on error
-   * Exception: none
-   */
-  static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) {
-    if (isSELinuxDisabled)
-      return false;
-
-    char * securityContext = NULL;
-    const char *constant_securityContext = NULL;
-
-    if (context != NULL) {
-      constant_securityContext = env->GetStringUTFChars(context, NULL);
-
-      // GetStringUTFChars returns const char * yet setfscreatecon needs char *
-      securityContext = const_cast<char *>(constant_securityContext);
+    ScopedLocalRef<jstring> contextStr(env, NULL);
+    if (ret != -1) {
+        contextStr.reset(env->NewStringUTF(context.get()));
     }
 
-    int ret;
-    if ((ret = setfscreatecon(securityContext)) == -1)
-      goto bail;
+    ALOGV("getPeerCon(%d) => %s", fd, contextStr.get());
+    return contextStr.release();
+}
 
-    ALOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context);
+/*
+ * Function: setFSCreateCon
+ * Purpose: set security context used for creating a new file system object
+ * Parameters:
+ *       context: security_context_t representing the new context of a file system object,
+ *                set to NULL to return to the default policy behavior
+ * Returns: true on success, false on error
+ * Exception: none
+ */
+static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-  bail:
-    if (constant_securityContext != NULL)
-      env->ReleaseStringUTFChars(context, constant_securityContext);
+    UniquePtr<ScopedUtfChars> context;
+    const char* context_c_str = NULL;
+    if (contextStr != NULL) {
+        context.reset(new ScopedUtfChars(env, contextStr));
+        context_c_str = context->c_str();
+        if (context_c_str == NULL) {
+            return false;
+        }
+    }
+
+    int ret = setfscreatecon(const_cast<char *>(context_c_str));
+
+    ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
 
     return (ret == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: setFileCon
-   * Purpose:  set the security context of a file object
-   * Parameters:
-   *       path: the location of the file system object
-   *       con: the new security context of the file system object
-   * Returns: true on success, false on error
-   * Exception: NullPointerException is thrown if either path or context strign are NULL
-   */
-  static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
-    if (isSELinuxDisabled)
-      return false;
-
-    if (path == NULL) {
-      throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
-      return false;
+/*
+ * Function: setFileCon
+ * Purpose:  set the security context of a file object
+ * Parameters:
+ *       path: the location of the file system object
+ *       context: the new security context of the file system object
+ * Returns: true on success, false on error
+ * Exception: NullPointerException is thrown if either path or context strign are NULL
+ */
+static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
+    if (isSELinuxDisabled) {
+        return false;
     }
 
-    if (con == NULL) {
-      throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
-      return false;
+    ScopedUtfChars path(env, pathStr);
+    if (path.c_str() == NULL) {
+        return false;
     }
 
-    const char *objectPath = env->GetStringUTFChars(path, NULL);
-    const char *constant_con = env->GetStringUTFChars(con, NULL);
+    ScopedUtfChars context(env, contextStr);
+    if (context.c_str() == NULL) {
+        return false;
+    }
 
     // GetStringUTFChars returns const char * yet setfilecon needs char *
-    char *newCon = const_cast<char *>(constant_con);
+    char *tmp = const_cast<char *>(context.c_str());
+    int ret = setfilecon(path.c_str(), tmp);
 
-    int ret;
-    if ((ret = setfilecon(objectPath, newCon)) == -1)
-      goto bail;
-
-    ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);
-
-  bail:
-    env->ReleaseStringUTFChars(path, objectPath);
-    env->ReleaseStringUTFChars(con, constant_con);
+    ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
     return (ret == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: getFileCon
-   * Purpose: retrieves the context associated with the given path in the file system
-   * Parameters:
-   *        path: given path in the file system
-   * Returns:
-   *        string representing the security context string of the file object
-   *        the string may be NULL if an error occured
-   * Exceptions: NullPointerException if the path object is null
-   */
-  static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
-    if (isSELinuxDisabled)
-      return NULL;
-
-    if (path == NULL) {
-      throw_NullPointerException(env, "Trying to check security context of a null path.");
-      return NULL;
+/*
+ * Function: getFileCon
+ * Purpose: retrieves the context associated with the given path in the file system
+ * Parameters:
+ *        path: given path in the file system
+ * Returns:
+ *        string representing the security context string of the file object
+ *        the string may be NULL if an error occured
+ * Exceptions: NullPointerException if the path object is null
+ */
+static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
+    if (isSELinuxDisabled) {
+        return NULL;
     }
 
-    const char *objectPath = env->GetStringUTFChars(path, NULL);
+    ScopedUtfChars path(env, pathStr);
+    if (path.c_str() == NULL) {
+        return NULL;
+    }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
+    security_context_t tmp;
+    int ret = getfilecon(path.c_str(), &tmp);
+    Unique_SecurityContext context(tmp);
 
-    if (getfilecon(objectPath, &context) == -1)
-      goto bail;
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);
+    ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
+    return securityString.release();
+}
 
-    securityString = env->NewStringUTF(context);
+/*
+ * Function: getCon
+ * Purpose: Get the context of the current process.
+ * Parameters: none
+ * Returns: a jstring representing the security context of the process,
+ *          the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getCon(JNIEnv *env, jobject) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
-  bail:
-    if (context != NULL)
-      freecon(context);
+    security_context_t tmp;
+    int ret = getcon(&tmp);
+    Unique_SecurityContext context(tmp);
 
-    env->ReleaseStringUTFChars(path, objectPath);
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    return securityString;
-  }
+    ALOGV("getCon() => %s", context.get());
+    return securityString.release();
+}
 
-  /*
-   * Function: getCon
-   * Purpose: Get the context of the current process.
-   * Parameters: none
-   * Returns: a jstring representing the security context of the process,
-   *          the jstring may be NULL if there was an error
-   * Exceptions: none
-   */
-  static jstring getCon(JNIEnv *env, jobject clazz) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getPidCon
+ * Purpose: Get the context of a process identified by its pid
+ * Parameters:
+ *            pid: a jint representing the process
+ * Returns: a jstring representing the security context of the pid,
+ *          the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
-    security_context_t context = NULL;
-    jstring securityString = NULL;
+    security_context_t tmp;
+    int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
+    Unique_SecurityContext context(tmp);
 
-    if (getcon(&context) == -1)
-      goto bail;
+    ScopedLocalRef<jstring> securityString(env, NULL);
+    if (ret != -1) {
+        securityString.reset(env->NewStringUTF(context.get()));
+    }
 
-    ALOGV("getCon: Successfully retrieved context '%s'", context);
+    ALOGV("getPidCon(%d) => %s", pid, context.get());
+    return securityString.release();
+}
 
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: getPidCon
-   * Purpose: Get the context of a process identified by its pid
-   * Parameters:
-   *            pid: a jint representing the process
-   * Returns: a jstring representing the security context of the pid,
-   *          the jstring may be NULL if there was an error
-   * Exceptions: none
-   */
-  static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) {
-    if (isSELinuxDisabled)
-      return NULL;
-
-    security_context_t context = NULL;
-    jstring securityString = NULL;
-
-    pid_t checkPid = (pid_t)pid;
-
-    if (getpidcon(checkPid, &context) == -1)
-      goto bail;
-
-    ALOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid);
-
-    securityString = env->NewStringUTF(context);
-
-  bail:
-    if (context != NULL)
-      freecon(context);
-
-    return securityString;
-  }
-
-  /*
-   * Function: getBooleanNames
-   * Purpose: Gets a list of the SELinux boolean names.
-   * Parameters: None
-   * Returns: an array of strings  containing the SELinux boolean names.
-   *          returns NULL string on error
-   * Exceptions: None
-   */
-  static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) {
-    if (isSELinuxDisabled)
-      return NULL;
+/*
+ * Function: getBooleanNames
+ * Purpose: Gets a list of the SELinux boolean names.
+ * Parameters: None
+ * Returns: an array of strings  containing the SELinux boolean names.
+ *          returns NULL string on error
+ * Exceptions: None
+ */
+static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
+    if (isSELinuxDisabled) {
+        return NULL;
+    }
 
     char **list;
-    int i, len, ret;
-    jclass stringClass;
-    jobjectArray stringArray = NULL;
+    int len;
+    if (security_get_boolean_names(&list, &len) == -1) {
+        return NULL;
+    }
 
-    if (security_get_boolean_names(&list, &len) == -1)
-      return NULL;
-
-    stringClass = env->FindClass("java/lang/String");
-    stringArray = env->NewObjectArray(len, stringClass, env->NewStringUTF(""));
-    for (i = 0; i < len; i++) {
-      jstring obj;
-      obj = env->NewStringUTF(list[i]);
-      env->SetObjectArrayElement(stringArray, i, obj);
-      env->DeleteLocalRef(obj);
-      free(list[i]);
+    jclass stringClass = env->FindClass("java/lang/String");
+    jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
+    for (int i = 0; i < len; i++) {
+        ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
+        env->SetObjectArrayElement(stringArray, i, obj.get());
+        free(list[i]);
     }
     free(list);
 
     return stringArray;
-  }
+}
 
-  /*
-   * Function: getBooleanValue
-   * Purpose: Gets the value for the given SELinux boolean name.
-   * Parameters:
-   *            String: The name of the SELinux boolean.
-   * Returns: a boolean: (true) boolean is set or (false) it is not.
-   * Exceptions: None
-   */
-  static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: getBooleanValue
+ * Purpose: Gets the value for the given SELinux boolean name.
+ * Parameters:
+ *            String: The name of the SELinux boolean.
+ * Returns: a boolean: (true) boolean is set or (false) it is not.
+ * Exceptions: None
+ */
+static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    const char *boolean_name;
-    int ret;
+    if (nameStr == NULL) {
+        return false;
+    }
 
-    if (name == NULL)
-      return false;
-    boolean_name = env->GetStringUTFChars(name, NULL);
-    ret = security_get_boolean_active(boolean_name);
-    env->ReleaseStringUTFChars(name, boolean_name);
+    ScopedUtfChars name(env, nameStr);
+    int ret = security_get_boolean_active(name.c_str());
+
+    ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
     return (ret == 1) ? true : false;
-  }
+}
 
-  /*
-   * Function: setBooleanNames
-   * Purpose: Sets the value for the given SELinux boolean name.
-   * Parameters:
-   *            String: The name of the SELinux boolean.
-   *            Boolean: The new value of the SELinux boolean.
-   * Returns: a boolean indicating whether or not the operation succeeded.
-   * Exceptions: None
-   */
-  static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) {
-    if (isSELinuxDisabled)
-      return false;
+/*
+ * Function: setBooleanNames
+ * Purpose: Sets the value for the given SELinux boolean name.
+ * Parameters:
+ *            String: The name of the SELinux boolean.
+ *            Boolean: The new value of the SELinux boolean.
+ * Returns: a boolean indicating whether or not the operation succeeded.
+ * Exceptions: None
+ */
+static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
+    if (isSELinuxDisabled) {
+        return false;
+    }
 
-    const char *boolean_name = NULL;
-    int ret;
+    if (nameStr == NULL) {
+        return false;
+    }
 
-    if (name == NULL)
-      return false;
-    boolean_name = env->GetStringUTFChars(name, NULL);
-    ret = security_set_boolean(boolean_name, (value) ? 1 : 0);
-    env->ReleaseStringUTFChars(name, boolean_name);
-    if (ret)
-      return false;
+    ScopedUtfChars name(env, nameStr);
+    int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
+    if (ret) {
+        return false;
+    }
 
-    if (security_commit_booleans() == -1)
-      return false;
+    if (security_commit_booleans() == -1) {
+        return false;
+    }
 
     return true;
-  }
+}
 
-  /*
-   * Function: checkSELinuxAccess
-   * Purpose: Check permissions between two security contexts.
-   * Parameters: scon: subject security context as a string
-   *             tcon: object security context as a string
-   *             tclass: object's security class name as a string
-   *             perm: permission name as a string
-   * Returns: boolean: (true) if permission was granted, (false) otherwise
-   * Exceptions: None
-   */
-  static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) {
-    if (isSELinuxDisabled)
-      return true;
+/*
+ * Function: checkSELinuxAccess
+ * Purpose: Check permissions between two security contexts.
+ * Parameters: subjectContextStr: subject security context as a string
+ *             objectContextStr: object security context as a string
+ *             objectClassStr: object's security class name as a string
+ *             permissionStr: permission name as a string
+ * Returns: boolean: (true) if permission was granted, (false) otherwise
+ * Exceptions: None
+ */
+static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
+        jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
+    if (isSELinuxDisabled) {
+        return true;
+    }
 
-    int accessGranted = -1;
+    ScopedUtfChars subjectContext(env, subjectContextStr);
+    if (subjectContext.c_str() == NULL) {
+        return false;
+    }
 
-    const char *const_scon, *const_tcon, *mytclass, *myperm;
-    char *myscon, *mytcon;
+    ScopedUtfChars objectContext(env, objectContextStr);
+    if (objectContext.c_str() == NULL) {
+        return false;
+    }
 
-    if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL)
-      goto bail;
+    ScopedUtfChars objectClass(env, objectClassStr);
+    if (objectClass.c_str() == NULL) {
+        return false;
+    }
 
-    const_scon = env->GetStringUTFChars(scon, NULL);
-    const_tcon = env->GetStringUTFChars(tcon, NULL);
-    mytclass   = env->GetStringUTFChars(tclass, NULL);
-    myperm     = env->GetStringUTFChars(perm, NULL);
+    ScopedUtfChars permission(env, permissionStr);
+    if (permission.c_str() == NULL) {
+        return false;
+    }
 
-    // selinux_check_access needs char* for some
-    myscon = const_cast<char *>(const_scon);
-    mytcon = const_cast<char *>(const_tcon);
+    char *tmp1 = const_cast<char *>(subjectContext.c_str());
+    char *tmp2 = const_cast<char *>(objectContext.c_str());
+    int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
+            NULL);
 
-    accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL);
+    ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
+            objectClass.c_str(), permission.c_str(), accessGranted);
 
-    ALOGV("selinux_check_access returned %d", accessGranted);
-
-    env->ReleaseStringUTFChars(scon, const_scon);
-    env->ReleaseStringUTFChars(tcon, const_tcon);
-    env->ReleaseStringUTFChars(tclass, mytclass);
-    env->ReleaseStringUTFChars(perm, myperm);
-
-  bail:
     return (accessGranted == 0) ? true : false;
-  }
+}
 
-  /*
-   * Function: native_restorecon
-   * Purpose: restore default SELinux security context
-   * Parameters: pathname: the pathname for the file to be relabeled
-   * Returns: boolean: (true) file label successfully restored, (false) otherwise
-   * Exceptions: none
-   */
-  static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
-    if (isSELinuxDisabled)
-      return true;
+/*
+ * Function: native_restorecon
+ * Purpose: restore default SELinux security context
+ * Parameters: pathname: the pathname for the file to be relabeled
+ * Returns: boolean: (true) file label successfully restored, (false) otherwise
+ * Exceptions: none
+ */
+static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
+    if (isSELinuxDisabled) {
+        return true;
+    }
 
-    const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
-    int ret = selinux_android_restorecon(file);
-    env->ReleaseStringUTFChars(pathname, file);
+    ScopedUtfChars pathname(env, pathnameStr);
+    if (pathname.c_str() == NULL) {
+        ALOGV("restorecon(%p) => threw exception", pathname);
+        return false;
+    }
+
+    int ret = selinux_android_restorecon(pathname.c_str());
+    ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
     return (ret == 0);
-  }
+}
 
-  /*
-   * JNI registration.
-   */
-  static JNINativeMethod method_table[] = {
-
+/*
+ * JNI registration.
+ */
+static JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
     { "getBooleanNames"          , "()[Ljava/lang/String;"                        , (void*)getBooleanNames  },
@@ -460,25 +439,25 @@
     { "setFileContext"           , "(Ljava/lang/String;Ljava/lang/String;)Z"      , (void*)setFileCon       },
     { "setFSCreateContext"       , "(Ljava/lang/String;)Z"                        , (void*)setFSCreateCon   },
     { "setSELinuxEnforce"        , "(Z)Z"                                         , (void*)setSELinuxEnforce},
-  };
+};
 
-  static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) {
     va_list ap;
     va_start(ap, fmt);
     LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap);
     va_end(ap);
     return 0;
-  }
+}
 
-  int register_android_os_SELinux(JNIEnv *env) {
+int register_android_os_SELinux(JNIEnv *env) {
     union selinux_callback cb;
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
     isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
 
-    return AndroidRuntime::registerNativeMethods(
-         env, "android/os/SELinux",
-         method_table, NELEM(method_table));
-  }
+    return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
+            NELEM(method_table));
+}
+
 }