diff options
author | Jooyung Han <jooyung@google.com> | 2024-02-05 21:02:15 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2024-02-05 21:02:15 +0000 |
commit | 94ae84ff54c68787517f449b79e1aedc7f2864a9 (patch) | |
tree | 19e9ad52bde9df7fdb89e84af3feb3336597e44e | |
parent | 77f3da22f3bf363c6dbc63c50c898a12f8f1df78 (diff) | |
parent | 205e282f43152ab2c73053f0ecc4b4d397663506 (diff) | |
download | native-94ae84ff54c68787517f449b79e1aedc7f2864a9.tar.gz |
Merge "Query methods for VINTF native instances" into main
-rw-r--r-- | cmds/servicemanager/Android.bp | 10 | ||||
-rw-r--r-- | cmds/servicemanager/NameUtil.h | 58 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManager.cpp | 84 | ||||
-rw-r--r-- | cmds/servicemanager/ServiceManagerUnittest.cpp | 39 | ||||
-rw-r--r-- | cmds/servicemanager/test_sm.cpp | 18 |
5 files changed, 195 insertions, 14 deletions
diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index e00c2a2b5a..3897197bd5 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -95,6 +95,16 @@ cc_test { static_libs: ["libgmock"], } +cc_test_host { + name: "servicemanager_unittest", + test_suites: ["general-tests"], + defaults: ["servicemanager_defaults"], + srcs: [ + "ServiceManagerUnittest.cpp", + ], + static_libs: ["libgmock"], +} + cc_fuzz { name: "servicemanager_fuzzer", defaults: [ diff --git a/cmds/servicemanager/NameUtil.h b/cmds/servicemanager/NameUtil.h new file mode 100644 index 0000000000..b08093960d --- /dev/null +++ b/cmds/servicemanager/NameUtil.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2023 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. + */ + +#pragma once + +#include <string> +#include <string_view> + +#include <android-base/strings.h> + +namespace android { + +#ifndef VENDORSERVICEMANAGER + +struct NativeName { + std::string package; + std::string instance; + + // Parse {package}/{instance} + static bool fill(std::string_view name, NativeName* nname) { + size_t slash = name.find('/'); + if (slash == std::string_view::npos) { + return false; + } + // no extra slashes + if (name.find('/', slash + 1) != std::string_view::npos) { + return false; + } + // every part should be non-empty + if (slash == 0 || slash + 1 == name.size()) { + return false; + } + // no dots in package + if (name.rfind('.', slash) != std::string_view::npos) { + return false; + } + nname->package = name.substr(0, slash); + nname->instance = name.substr(slash + 1); + return true; + } +}; + +#endif + +} // namespace android diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index f2f0a0f037..bf85e61583 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -35,6 +35,8 @@ #include <vintf/constants.h> #endif // !VENDORSERVICEMANAGER +#include "NameUtil.h" + using ::android::binder::Status; using ::android::internal::Stability; @@ -84,6 +86,10 @@ static bool forEachManifest(const std::function<bool(const ManifestWithDescripti return false; } +static std::string getNativeInstanceName(const vintf::ManifestInstance& instance) { + return instance.package() + "/" + instance.instance(); +} + struct AidlName { std::string package; std::string iface; @@ -105,7 +111,26 @@ struct AidlName { } }; +static std::string getAidlInstanceName(const vintf::ManifestInstance& instance) { + return instance.package() + "." + instance.interface() + "/" + instance.instance(); +} + static bool isVintfDeclared(const std::string& name) { + NativeName nname; + if (NativeName::fill(name, &nname)) { + bool found = forEachManifest([&](const ManifestWithDescription& mwd) { + if (mwd.manifest->hasNativeInstance(nname.package, nname.instance)) { + ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description); + return true; // break + } + return false; // continue + }); + if (!found) { + ALOGI("Could not find %s in the VINTF manifest.", name.c_str()); + } + return found; + } + AidlName aname; if (!AidlName::fill(name, &aname)) return false; @@ -144,6 +169,24 @@ static bool isVintfDeclared(const std::string& name) { } static std::optional<std::string> getVintfUpdatableApex(const std::string& name) { + NativeName nname; + if (NativeName::fill(name, &nname)) { + std::optional<std::string> updatableViaApex; + + forEachManifest([&](const ManifestWithDescription& mwd) { + bool cont = mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + if (manifestInstance.format() != vintf::HalFormat::NATIVE) return true; + if (manifestInstance.package() != nname.package) return true; + if (manifestInstance.instance() != nname.instance) return true; + updatableViaApex = manifestInstance.updatableViaApex(); + return false; // break (libvintf uses opposite convention) + }); + return !cont; + }); + + return updatableViaApex; + } + AidlName aname; if (!AidlName::fill(name, &aname)) return std::nullopt; @@ -164,24 +207,25 @@ static std::optional<std::string> getVintfUpdatableApex(const std::string& name) return updatableViaApex; } -static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) { - std::vector<std::string> instances; +static std::vector<std::string> getVintfUpdatableNames(const std::string& apexName) { + std::vector<std::string> names; forEachManifest([&](const ManifestWithDescription& mwd) { mwd.manifest->forEachInstance([&](const auto& manifestInstance) { - if (manifestInstance.format() == vintf::HalFormat::AIDL && - manifestInstance.updatableViaApex().has_value() && + if (manifestInstance.updatableViaApex().has_value() && manifestInstance.updatableViaApex().value() == apexName) { - std::string aname = manifestInstance.package() + "." + - manifestInstance.interface() + "/" + manifestInstance.instance(); - instances.push_back(aname); + if (manifestInstance.format() == vintf::HalFormat::NATIVE) { + names.push_back(getNativeInstanceName(manifestInstance)); + } else if (manifestInstance.format() == vintf::HalFormat::AIDL) { + names.push_back(getAidlInstanceName(manifestInstance)); + } } return true; // continue (libvintf uses opposite convention) }); return false; // continue }); - return instances; + return names; } static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) { @@ -216,6 +260,18 @@ static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& n static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { + // This might be a package for native instance. + std::vector<std::string> ret; + (void)forEachManifest([&](const ManifestWithDescription& mwd) { + auto instances = mwd.manifest->getNativeInstances(interface); + ret.insert(ret.end(), instances.begin(), instances.end()); + return false; // continue + }); + // If found, return it without error log. + if (!ret.empty()) { + return ret; + } + ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) " "but got: %s", interface.c_str()); @@ -593,20 +649,20 @@ Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& ape std::vector<std::string>* outReturn) { auto ctx = mAccess->getCallingContext(); - std::vector<std::string> apexUpdatableInstances; + std::vector<std::string> apexUpdatableNames; #ifndef VENDORSERVICEMANAGER - apexUpdatableInstances = getVintfUpdatableInstances(apexName); + apexUpdatableNames = getVintfUpdatableNames(apexName); #endif outReturn->clear(); - for (const std::string& instance : apexUpdatableInstances) { - if (mAccess->canFind(ctx, instance)) { - outReturn->push_back(instance); + for (const std::string& name : apexUpdatableNames) { + if (mAccess->canFind(ctx, name)) { + outReturn->push_back(name); } } - if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) { + if (outReturn->size() == 0 && apexUpdatableNames.size() != 0) { return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denied."); } diff --git a/cmds/servicemanager/ServiceManagerUnittest.cpp b/cmds/servicemanager/ServiceManagerUnittest.cpp new file mode 100644 index 0000000000..39d20b0025 --- /dev/null +++ b/cmds/servicemanager/ServiceManagerUnittest.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2023 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 <gtest/gtest.h> + +#include "NameUtil.h" + +namespace android { + +TEST(ServiceManager, NativeName) { + NativeName nname; + EXPECT_TRUE(NativeName::fill("mapper/default", &nname)); + EXPECT_EQ("mapper", nname.package); + EXPECT_EQ("default", nname.instance); +} + +TEST(ServiceManager, NativeName_Malformed) { + NativeName nname; + EXPECT_FALSE(NativeName::fill("mapper", &nname)); + EXPECT_FALSE(NativeName::fill("mapper/", &nname)); + EXPECT_FALSE(NativeName::fill("/default", &nname)); + EXPECT_FALSE(NativeName::fill("mapper/default/0", &nname)); + EXPECT_FALSE(NativeName::fill("aidl.like.IType/default", &nname)); +} + +} // namespace android diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 97e500d0a7..b57505302c 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -361,6 +361,24 @@ TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { EXPECT_EQ(std::vector<std::string>{}, names); } +TEST(Vintf, IsDeclared_native) { + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; + + auto sm = getPermissiveServiceManager(); + bool declared = false; + EXPECT_TRUE(sm->isDeclared("mapper/minigbm", &declared).isOk()); + EXPECT_TRUE(declared); +} + +TEST(Vintf, GetDeclaredInstances_native) { + if (!isCuttlefishPhone()) GTEST_SKIP() << "Skipping non-Cuttlefish-phone devices"; + + auto sm = getPermissiveServiceManager(); + std::vector<std::string> instances; + EXPECT_TRUE(sm->getDeclaredInstances("mapper", &instances).isOk()); + EXPECT_EQ(std::vector<std::string>{"minigbm"}, instances); +} + class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); |