restorecon_recursive("/sys") speed boot time

Currently, the restorecon_recursive("/sys") call in
init.c takes approx 2 seconds on hammerhead. This change
reduces the delay to 1.2 seconds.

1) Avoid double stat call when using nftw (time savings
of 0.3 seconds)
2) Avoid the repeated calls to is_selinux_enabled() (time
savings of 0.5 seconds)

Avoid calling lsetfilecon if the file is already properly
labeled. This doesn't speed up the restorecon on /sys,
but it should help when handling files on /data.

Bug: 11640230
Change-Id: Ie212ce4f4acade208c5676d60c1f03f50e2388a4
diff --git a/init/util.c b/init/util.c
index 9aaa77d..5efd5be 100644
--- a/init/util.c
+++ b/init/util.c
@@ -524,31 +524,50 @@
     return rc;
 }
 
-int restorecon(const char *pathname)
+static int restorecon_sb(const char *pathname, const struct stat *sb)
 {
     char *secontext = NULL;
-    struct stat sb;
+    char *oldsecontext = NULL;
     int i;
 
+    if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
+        return -errno;
+
+    if (lgetfilecon(pathname, &oldsecontext) < 0) {
+        freecon(secontext);
+        return -errno;
+    }
+
+    if (strcmp(oldsecontext, secontext) != 0) {
+        if (lsetfilecon(pathname, secontext) < 0) {
+            freecon(oldsecontext);
+            freecon(secontext);
+            return -errno;
+        }
+    }
+    freecon(oldsecontext);
+    freecon(secontext);
+    return 0;
+}
+
+int restorecon(const char *pathname)
+{
+    struct stat sb;
+
     if (is_selinux_enabled() <= 0 || !sehandle)
         return 0;
 
     if (lstat(pathname, &sb) < 0)
         return -errno;
-    if (selabel_lookup(sehandle, &secontext, pathname, sb.st_mode) < 0)
-        return -errno;
-    if (lsetfilecon(pathname, secontext) < 0) {
-        freecon(secontext);
-        return -errno;
-    }
-    freecon(secontext);
-    return 0;
+
+    return restorecon_sb(pathname, &sb);
 }
 
 static int nftw_restorecon(const char* filename, const struct stat* statptr,
-    int fileflags, struct FTW* pftw)
+    int fileflags __attribute__((unused)),
+    struct FTW* pftw __attribute__((unused)))
 {
-    restorecon(filename);
+    restorecon_sb(filename, statptr);
     return 0;
 }
 
@@ -556,5 +575,9 @@
 {
     int fd_limit = 20;
     int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;
+
+    if (is_selinux_enabled() <= 0 || !sehandle)
+        return 0;
+
     return nftw(pathname, nftw_restorecon, fd_limit, flags);
 }