Add a method to load vendor_service_context only.

This is used by vndservicemanager, which will only
have access to the vndservice_contexts on the vendor
partition.

Bug: 36052864
Test: vndservicemanager can load the context
Change-Id: Ifd5caa4f74236184ef970ce39a8be227c50b48d4
diff --git a/libselinux/exported.map b/libselinux/exported.map
index 94087cb..35dfae1 100644
--- a/libselinux/exported.map
+++ b/libselinux/exported.map
@@ -20,6 +20,7 @@
     selinux_android_setcontext;
     selinux_android_set_sehandle;
     selinux_android_service_context_handle;
+    selinux_android_vendor_service_context_handle;
     selinux_check_access;
     security_getenforce;
     security_setenforce;
diff --git a/libselinux/include/selinux/android.h b/libselinux/include/selinux/android.h
index 78bb7db..93e7574 100644
--- a/libselinux/include/selinux/android.h
+++ b/libselinux/include/selinux/android.h
@@ -17,6 +17,8 @@
 
 extern struct selabel_handle* selinux_android_service_context_handle(void);
 
+extern struct selabel_handle* selinux_android_vendor_service_context_handle(void);
+
 extern void selinux_android_set_sehandle(const struct selabel_handle *hndl);
 
 extern int selinux_android_load_policy(void);
diff --git a/libselinux/src/android/android.c b/libselinux/src/android/android.c
index 2978490..4c61b71 100644
--- a/libselinux/src/android/android.c
+++ b/libselinux/src/android/android.c
@@ -86,6 +86,13 @@
     { SELABEL_OPT_PATH, "/nonplat_service_contexts" }
 };
 
+static const struct selinux_opt seopts_vndservice =
+    { SELABEL_OPT_PATH, "/vendor/etc/selinux/vndservice_contexts" };
+
+static const struct selinux_opt seopts_vndservice_rootfs =
+    { SELABEL_OPT_PATH, "/vndservice_contexts" };
+
+
 enum levelFrom {
 	LEVELFROM_NONE,
 	LEVELFROM_APP,
@@ -1647,9 +1654,28 @@
     return sehandle;
 }
 
-struct selabel_handle* selinux_android_service_context_handle(void)
+struct selabel_handle* selinux_android_service_open_context_handle(const struct selinux_opt* seopts_service,
+                                                                   unsigned nopts)
 {
     struct selabel_handle* sehandle;
+
+    sehandle = selabel_open(SELABEL_CTX_ANDROID_SERVICE,
+            seopts_service, nopts);
+
+    if (!sehandle) {
+        selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
+                __FUNCTION__, strerror(errno));
+        return NULL;
+    }
+    selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from:\n");
+    for (unsigned i = 0; i < nopts; i++) {
+        selinux_log(SELINUX_INFO, "    %s\n", seopts_service[i].value);
+    }
+    return sehandle;
+}
+
+struct selabel_handle* selinux_android_service_context_handle(void)
+{
     const struct selinux_opt* seopts_service;
 
     // Prefer files from /system & /vendor, fall back to files from /
@@ -1659,18 +1685,20 @@
         seopts_service = seopts_service_rootfs;
     }
 
-    sehandle = selabel_open(SELABEL_CTX_ANDROID_SERVICE,
-            seopts_service, 2);
+    // TODO(b/36866029) full treble devices can't load non-plat
+    return selinux_android_service_open_context_handle(seopts_service, 2);
+}
 
-    if (!sehandle) {
-        selinux_log(SELINUX_ERROR, "%s: Error getting service context handle (%s)\n",
-                __FUNCTION__, strerror(errno));
-        return NULL;
+struct selabel_handle* selinux_android_vendor_service_context_handle(void)
+{
+    const struct selinux_opt* seopts_service;
+    if (access(seopts_vndservice.value, R_OK) != -1) {
+        seopts_service = &seopts_vndservice;
+    } else {
+        seopts_service = &seopts_vndservice_rootfs;
     }
-    selinux_log(SELINUX_INFO, "SELinux: Loaded service_contexts from %s & %s.\n",
-            seopts_service[0].value, seopts_service[1].value);
 
-    return sehandle;
+    return selinux_android_service_open_context_handle(seopts_service, 1);
 }
 
 void selinux_android_set_sehandle(const struct selabel_handle *hndl)