lshal: add libprocpartition

... that determines the partition of a process.

Bug: 71802285
Test: lshal_test
Test: vts_treble_vintf_test

Change-Id: I7aa0b773be65a3111c0417de1f0e79c8e12ef6fb
diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp
new file mode 100644
index 0000000..9592111
--- /dev/null
+++ b/cmds/lshal/libprocpartition/Android.bp
@@ -0,0 +1,30 @@
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_static {
+    name: "libprocpartition",
+    shared_libs: [
+        "libbase",
+    ],
+    srcs: [
+        "procpartition.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_include_dirs: [
+        "include",
+    ]
+}
diff --git a/cmds/lshal/libprocpartition/include/procpartition/procpartition.h b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
new file mode 100644
index 0000000..7e86432
--- /dev/null
+++ b/cmds/lshal/libprocpartition/include/procpartition/procpartition.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+#define FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
+
+#include <sys/types.h>
+
+#include <string>
+#include <iostream>
+
+namespace android {
+namespace procpartition {
+
+enum class Partition {
+    UNKNOWN = 0,
+    SYSTEM,
+    VENDOR,
+    ODM
+};
+
+std::ostream& operator<<(std::ostream& os, Partition p);
+Partition parsePartition(const std::string& s);
+
+// Return the path that /proc/<pid>/exe points to.
+std::string getExe(pid_t pid);
+// Return the content of /proc/<pid>/cmdline.
+std::string getCmdline(pid_t pid);
+// Infer the partition of a process from /proc/<pid>/exe and /proc/<pid>/cmdline.
+Partition getPartition(pid_t pid);
+
+}  // namespace procpartition
+}  // namespace android
+
+#endif  // FRAMEWORK_NATIVE_CMDS_LSHAL_PROCPARTITION_H_
diff --git a/cmds/lshal/libprocpartition/procpartition.cpp b/cmds/lshal/libprocpartition/procpartition.cpp
new file mode 100644
index 0000000..8ca458a
--- /dev/null
+++ b/cmds/lshal/libprocpartition/procpartition.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <procpartition/procpartition.h>
+
+#include <android-base/file.h>
+
+namespace android {
+namespace procpartition {
+
+std::ostream& operator<<(std::ostream& os, Partition p) {
+    switch (p) {
+        case Partition::SYSTEM: return os << "system";
+        case Partition::VENDOR: return os << "vendor";
+        case Partition::ODM: return os << "odm";
+        case Partition::UNKNOWN: // fallthrough
+        default:
+            return os << "(unknown)";
+    }
+}
+
+std::string getExe(pid_t pid) {
+    std::string exe;
+    std::string real;
+    if (!android::base::Readlink("/proc/" + std::to_string(pid) + "/exe", &exe)) {
+        return "";
+    }
+    if (!android::base::Realpath(exe, &real)) {
+        return "";
+    }
+    return real;
+}
+
+std::string getCmdline(pid_t pid) {
+    std::string content;
+    if (!android::base::ReadFileToString("/proc/" + std::to_string(pid) + "/cmdline", &content,
+                                         false /* follow symlinks */)) {
+        return "";
+    }
+    return content;
+}
+
+Partition parsePartition(const std::string& s) {
+    if (s == "system") {
+        return Partition::SYSTEM;
+    }
+    if (s == "vendor") {
+        return Partition::VENDOR;
+    }
+    if (s == "odm") {
+        return Partition::ODM;
+    }
+    return Partition::UNKNOWN;
+}
+
+Partition getPartitionFromRealpath(const std::string& path) {
+    if (path == "/system/bin/app_process64" ||
+        path == "/system/bin/app_process32") {
+
+        return Partition::UNKNOWN; // cannot determine
+    }
+    size_t backslash = path.find_first_of('/', 1);
+    std::string partition = (backslash != std::string::npos) ? path.substr(1, backslash - 1) : path;
+
+    return parsePartition(partition);
+}
+
+Partition getPartitionFromCmdline(pid_t pid) {
+    const auto& cmdline = getCmdline(pid);
+    if (cmdline == "system_server") {
+        return Partition::SYSTEM;
+    }
+    if (cmdline.empty() || cmdline.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(cmdline);
+}
+
+Partition getPartitionFromExe(pid_t pid) {
+    const auto& real = getExe(pid);
+    if (real.empty() || real.front() != '/') {
+        return Partition::UNKNOWN;
+    }
+    return getPartitionFromRealpath(real);
+}
+
+
+Partition getPartition(pid_t pid) {
+    Partition partition = getPartitionFromExe(pid);
+    if (partition == Partition::UNKNOWN) {
+        partition = getPartitionFromCmdline(pid);
+    }
+    return partition;
+}
+
+}  // namespace procpartition
+}  // namespace android