Merge changes from topic "lshal_init_vintf_type"
* changes:
lshal --init-vintf: can specify manifest partition
lshal: add libprocpartition
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 409c206..93d878b 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -24,6 +24,9 @@
"libhidl-gen-utils",
"libvintf",
],
+ static_libs: [
+ "libprocpartition",
+ ],
srcs: [
"DebugCommand.cpp",
"HelpCommand.cpp",
@@ -45,10 +48,14 @@
shared_libs: [
"libbase",
"libhidlbase",
+ "libhidl-gen-utils",
"libhidltransport",
"liblshal",
"libutils",
],
+ static_libs: [
+ "libprocpartition",
+ ],
cflags: ["-Wall", "-Werror"],
}
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index fab13a0..b9e0139 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -25,6 +25,7 @@
#include <sstream>
#include <regex>
+#include <android-base/file.h>
#include <android-base/parseint.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
#include <hidl-hash/Hash.h>
@@ -32,6 +33,7 @@
#include <private/android_filesystem_config.h>
#include <sys/stat.h>
#include <vintf/HalManifest.h>
+#include <vintf/parse_string.h>
#include <vintf/parse_xml.h>
#include "Lshal.h"
@@ -48,6 +50,10 @@
namespace android {
namespace lshal {
+vintf::SchemaType toSchemaType(Partition p) {
+ return (p == Partition::SYSTEM) ? vintf::SchemaType::FRAMEWORK : vintf::SchemaType::DEVICE;
+}
+
NullableOStream<std::ostream> ListCommand::out() const {
return mLshal.out();
}
@@ -64,13 +70,7 @@
}
std::string ListCommand::parseCmdline(pid_t pid) const {
- std::ifstream ifs("/proc/" + std::to_string(pid) + "/cmdline");
- std::string cmdline;
- if (!ifs.is_open()) {
- return "";
- }
- ifs >> cmdline;
- return cmdline;
+ return android::procpartition::getCmdline(pid);
}
const std::string &ListCommand::getCmdline(pid_t pid) {
@@ -89,6 +89,42 @@
}), pids->end());
}
+Partition ListCommand::getPartition(pid_t pid) {
+ auto it = mPartitions.find(pid);
+ if (it != mPartitions.end()) {
+ return it->second;
+ }
+ Partition partition = android::procpartition::getPartition(pid);
+ mPartitions.emplace(pid, partition);
+ return partition;
+}
+
+// Give sensible defaults when nothing can be inferred from runtime.
+// process: Partition inferred from executable location or cmdline.
+Partition ListCommand::resolvePartition(Partition process, const FQName& fqName) const {
+ if (fqName.inPackage("vendor") ||
+ fqName.inPackage("com")) {
+ return Partition::VENDOR;
+ }
+
+ if (fqName.inPackage("android.frameworks") ||
+ fqName.inPackage("android.system") ||
+ fqName.inPackage("android.hidl")) {
+ return Partition::SYSTEM;
+ }
+
+ // Some android.hardware HALs are served from system. Check the value from executable
+ // location / cmdline first.
+ if (fqName.inPackage("android.hardware")) {
+ if (process != Partition::UNKNOWN) {
+ return process;
+ }
+ return Partition::VENDOR;
+ }
+
+ return process;
+}
+
static bool scanBinderContext(pid_t pid,
const std::string &contextName,
std::function<void(const std::string&)> eachLine) {
@@ -209,6 +245,9 @@
entry.clientCmdlines.push_back(this->getCmdline(pid));
}
}
+ for (TableEntry& entry : table) {
+ entry.partition = getPartition(entry.serverPid);
+ }
});
// use a double for loop here because lshal doesn't care about efficiency.
for (TableEntry &packageEntry : mImplementationsTable) {
@@ -256,18 +295,10 @@
void ListCommand::dumpVintf(const NullableOStream<std::ostream>& out) const {
using vintf::operator|=;
- out << "<!-- " << std::endl
- << " This is a skeleton device manifest. Notes: " << std::endl
- << " 1. android.hidl.*, android.frameworks.*, android.system.* are not included." << std::endl
- << " 2. If a HAL is supported in both hwbinder and passthrough transport, " << std::endl
- << " only hwbinder is shown." << std::endl
- << " 3. It is likely that HALs in passthrough transport does not have" << std::endl
- << " <interface> declared; users will have to write them by hand." << std::endl
- << " 4. A HAL with lower minor version can be overridden by a HAL with" << std::endl
- << " higher minor version if they have the same name and major version." << std::endl
- << "-->" << std::endl;
+ using vintf::operator<<;
vintf::HalManifest manifest;
+ manifest.setType(toSchemaType(mVintfPartition));
forEachTable([this, &manifest] (const Table &table) {
for (const TableEntry &entry : table) {
@@ -284,12 +315,23 @@
<< "' is not a valid FQName." << std::endl;
continue;
}
- // Strip out system libs.
- if (fqName.inPackage("android.hidl") ||
- fqName.inPackage("android.frameworks") ||
- fqName.inPackage("android.system")) {
+
+ if (fqName.package() == gIBaseFqName.package()) {
+ continue; // always remove IBase from manifest
+ }
+
+ Partition partition = resolvePartition(entry.partition, fqName);
+
+ if (partition == Partition::UNKNOWN) {
+ err() << "Warning: Cannot guess the partition of instance " << fqInstanceName
+ << ". It is removed from the generated manifest." << std::endl;
continue;
}
+
+ if (partition != mVintfPartition) {
+ continue; // strip out instances that is in a different partition.
+ }
+
std::string interfaceName =
&table == &mImplementationsTable ? "" : fqName.name();
std::string instanceName =
@@ -361,9 +403,22 @@
}
}
});
+ out << "<!-- " << std::endl
+ << " This is a skeleton " << manifest.type() << " manifest. Notes: " << std::endl
+ << INIT_VINTF_NOTES
+ << "-->" << std::endl;
out << vintf::gHalManifestConverter(manifest, vintf::SerializeFlag::HALS_ONLY);
}
+std::string ListCommand::INIT_VINTF_NOTES{
+ " 1. If a HAL is supported in both hwbinder and passthrough transport, \n"
+ " only hwbinder is shown.\n"
+ " 2. It is likely that HALs in passthrough transport does not have\n"
+ " <interface> declared; users will have to write them by hand.\n"
+ " 3. A HAL with lower minor version can be overridden by a HAL with\n"
+ " higher minor version if they have the same name and major version.\n"
+};
+
static Architecture fromBaseArchitecture(::android::hidl::base::V1_0::DebugInfo::Architecture a) {
switch (a) {
case ::android::hidl::base::V1_0::DebugInfo::Architecture::IS_64BIT:
@@ -710,9 +765,18 @@
// long options without short alternatives
mOptions.push_back({'\0', "init-vintf", no_argument, v++, [](ListCommand* thiz, const char* arg) {
thiz->mVintf = true;
+ if (thiz->mVintfPartition == Partition::UNKNOWN)
+ thiz->mVintfPartition = Partition::VENDOR;
if (arg) thiz->mFileOutputPath = arg;
return OK;
}, "form a skeleton HAL manifest to specified file,\nor stdout if no file specified."});
+ mOptions.push_back({'\0', "init-vintf-partition", required_argument, v++, [](ListCommand* thiz, const char* arg) {
+ if (!arg) return USAGE;
+ thiz->mVintfPartition = android::procpartition::parsePartition(arg);
+ if (thiz->mVintfPartition == Partition::UNKNOWN) return USAGE;
+ return OK;
+ }, "Specify the partition of the HAL manifest\ngenerated by --init-vintf.\n"
+ "Valid values are 'system', 'vendor', and 'odm'. Default is 'vendor'."});
mOptions.push_back({'\0', "sort", required_argument, v++, [](ListCommand* thiz, const char* arg) {
if (strcmp(arg, "interface") == 0 || strcmp(arg, "i") == 0) {
thiz->mSortColumn = TableEntry::sortByInterfaceName;
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 7e252fc..1e85ea0 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -26,6 +26,7 @@
#include <android-base/macros.h>
#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <hidl-util/FQName.h>
#include "Command.h"
#include "NullableOStream.h"
@@ -75,6 +76,8 @@
// key: value returned by getopt_long
using RegisteredOptions = std::vector<RegisteredOption>;
+ static std::string INIT_VINTF_NOTES;
+
protected:
Status parseArgs(const Arg &arg);
Status fetch();
@@ -104,10 +107,14 @@
// Read and return /proc/{pid}/cmdline.
virtual std::string parseCmdline(pid_t pid) const;
// Return /proc/{pid}/cmdline if it exists, else empty string.
- const std::string &getCmdline(pid_t pid);
+ const std::string& getCmdline(pid_t pid);
// Call getCmdline on all pid in pids. If it returns empty string, the process might
// have died, and the pid is removed from pids.
void removeDeadProcesses(Pids *pids);
+
+ virtual Partition getPartition(pid_t pid);
+ Partition resolvePartition(Partition processPartition, const FQName& fqName) const;
+
void forEachTable(const std::function<void(Table &)> &f);
void forEachTable(const std::function<void(const Table &)> &f) const;
@@ -125,8 +132,9 @@
bool mEmitDebugInfo = false;
- // If true, output in VINTF format.
+ // If true, output in VINTF format. Output only entries from the specified partition.
bool mVintf = false;
+ Partition mVintfPartition = Partition::UNKNOWN;
// If true, explanatory text are not emitted.
bool mNeat = false;
@@ -139,6 +147,9 @@
// Cache for getPidInfo.
std::map<pid_t, PidInfo> mCachedPidInfos;
+ // Cache for getPartition.
+ std::map<pid_t, Partition> mPartitions;
+
RegisteredOptions mOptions;
// All selected columns
std::vector<TableColumnType> mSelectedColumns;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 69206cc..24ea438 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -23,11 +23,14 @@
#include <vector>
#include <iostream>
+#include <procpartition/procpartition.h>
+
#include "TextTable.h"
namespace android {
namespace lshal {
+using android::procpartition::Partition;
using Pids = std::vector<int32_t>;
enum : unsigned int {
@@ -77,6 +80,7 @@
Architecture arch{ARCH_UNKNOWN};
// empty: unknown, all zeros: unreleased, otherwise: released
std::string hash{};
+ Partition partition{Partition::UNKNOWN};
static bool sortByInterfaceName(const TableEntry &a, const TableEntry &b) {
return a.interfaceName < b.interfaceName;
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
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 9220fc0..4fa941e 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -206,6 +206,7 @@
MOCK_METHOD0(postprocess, void());
MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
+ MOCK_METHOD1(getPartition, Partition(pid_t));
};
class ListParseArgsTest : public ::testing::Test {
@@ -333,6 +334,7 @@
table.setDescription("[fake description " + std::to_string(i++) + "]");
});
}));
+ ON_CALL(*mockList, getPartition(_)).WillByDefault(Return(Partition::VENDOR));
}
void initMockServiceManager() {
@@ -418,17 +420,7 @@
TEST_F(ListTest, DumpVintf) {
const std::string expected =
"<!-- \n"
- " This is a skeleton device manifest. Notes: \n"
- " 1. android.hidl.*, android.frameworks.*, android.system.* are not included.\n"
- " 2. If a HAL is supported in both hwbinder and passthrough transport, \n"
- " only hwbinder is shown.\n"
- " 3. It is likely that HALs in passthrough transport does not have\n"
- " <interface> declared; users will have to write them by hand.\n"
- " 4. A HAL with lower minor version can be overridden by a HAL with\n"
- " higher minor version if they have the same name and major version.\n"
- " 5. sepolicy version is set to 0.0. It is recommended that the entry\n"
- " is removed from the manifest file and written by assemble_vintf\n"
- " at build time.\n"
+ " This is a skeleton device manifest. Notes: \n" + ListCommand::INIT_VINTF_NOTES +
"-->\n"
"<manifest version=\"1.0\" type=\"device\">\n"
" <hal format=\"hidl\">\n"
@@ -477,9 +469,6 @@
" <transport arch=\"32\">passthrough</transport>\n"
" <version>6.0</version>\n"
" </hal>\n"
- " <sepolicy>\n"
- " <version>0.0</version>\n"
- " </sepolicy>\n"
"</manifest>\n";
optind = 1; // mimic Lshal::parseArg()