Add libbinderdebug
Allows lshal and dumpsys to share the code to get Binder PID info. Test: atest libbinderdebug_test lshal_test Test: diff output of lshal before and after this CL Bug: 140639610 Change-Id: I04dbe2509673502502ac849ef4ae74147404fc43
This commit is contained in:
parent
f5c89f5911
commit
c03e3aa3cd
12 changed files with 351 additions and 105 deletions
|
@ -16,6 +16,7 @@ cc_library_static {
|
|||
name: "liblshal",
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinderdebug",
|
||||
"libcutils",
|
||||
"libutils",
|
||||
"libhidlbase",
|
||||
|
@ -47,6 +48,7 @@ cc_defaults {
|
|||
name: "lshal_defaults",
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinderdebug",
|
||||
"libcutils",
|
||||
"libutils",
|
||||
"libhidlbase",
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/parseint.h>
|
||||
#include <android/hidl/manager/1.0/IServiceManager.h>
|
||||
#include <hidl-hash/Hash.h>
|
||||
#include <hidl-util/FQName.h>
|
||||
|
@ -203,97 +202,14 @@ VintfInfo ListCommand::getVintfInfo(const std::string& fqInstanceName,
|
|||
lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
|
||||
}
|
||||
|
||||
static bool scanBinderContext(pid_t pid,
|
||||
const std::string &contextName,
|
||||
std::function<void(const std::string&)> eachLine) {
|
||||
std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
|
||||
if (!ifs.is_open()) {
|
||||
ifs.open("/d/binder/proc/" + std::to_string(pid));
|
||||
if (!ifs.is_open()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static const std::regex kContextLine("^context (\\w+)$");
|
||||
|
||||
bool isDesiredContext = false;
|
||||
std::string line;
|
||||
std::smatch match;
|
||||
while(getline(ifs, line)) {
|
||||
if (std::regex_search(line, match, kContextLine)) {
|
||||
isDesiredContext = match.str(1) == contextName;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isDesiredContext) {
|
||||
continue;
|
||||
}
|
||||
|
||||
eachLine(line);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ListCommand::getPidInfo(
|
||||
pid_t serverPid, PidInfo *pidInfo) const {
|
||||
static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
|
||||
static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
|
||||
|
||||
std::smatch match;
|
||||
return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
|
||||
if (std::regex_search(line, match, kReferencePrefix)) {
|
||||
const std::string &ptrString = "0x" + match.str(2); // use number after c
|
||||
uint64_t ptr;
|
||||
if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
|
||||
// Should not reach here, but just be tolerant.
|
||||
err() << "Could not parse number " << ptrString << std::endl;
|
||||
return;
|
||||
}
|
||||
const std::string proc = " proc ";
|
||||
auto pos = line.rfind(proc);
|
||||
if (pos != std::string::npos) {
|
||||
for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
|
||||
int32_t pid;
|
||||
if (!::android::base::ParseInt(pidStr, &pid)) {
|
||||
err() << "Could not parse number " << pidStr << std::endl;
|
||||
return;
|
||||
}
|
||||
pidInfo->refPids[ptr].push_back(pid);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (std::regex_search(line, match, kThreadPrefix)) {
|
||||
// "1" is waiting in binder driver
|
||||
// "2" is poll. It's impossible to tell if these are in use.
|
||||
// and HIDL default code doesn't use it.
|
||||
bool isInUse = match.str(1) != "1";
|
||||
// "0" is a thread that has called into binder
|
||||
// "1" is looper thread
|
||||
// "2" is main looper thread
|
||||
bool isHwbinderThread = match.str(2) != "0";
|
||||
|
||||
if (!isHwbinderThread) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isInUse) {
|
||||
pidInfo->threadUsage++;
|
||||
}
|
||||
|
||||
pidInfo->threadCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
// not reference or thread line
|
||||
return;
|
||||
});
|
||||
pid_t serverPid, BinderPidInfo *pidInfo) const {
|
||||
const auto& status = getBinderPidInfo(BinderDebugContext::HWBINDER, serverPid, pidInfo);
|
||||
return status == OK;
|
||||
}
|
||||
|
||||
const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
|
||||
auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
|
||||
const BinderPidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
|
||||
auto pair = mCachedPidInfos.insert({serverPid, BinderPidInfo{}});
|
||||
if (pair.second /* did insertion take place? */) {
|
||||
if (!getPidInfo(serverPid, &pair.first->second)) {
|
||||
return nullptr;
|
||||
|
@ -727,7 +643,7 @@ Status ListCommand::fetchBinderizedEntry(const sp<IServiceManager> &manager,
|
|||
entry->arch = fromBaseArchitecture(debugInfo.arch);
|
||||
|
||||
if (debugInfo.pid != NO_PID) {
|
||||
const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
|
||||
const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
|
||||
if (pidInfo == nullptr) {
|
||||
handleError(IO_ERROR,
|
||||
"no information for PID " + std::to_string(debugInfo.pid) +
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include <android-base/macros.h>
|
||||
#include <android/hidl/manager/1.0/IServiceManager.h>
|
||||
#include <binderdebug/BinderDebug.h>
|
||||
#include <hidl-util/FqInstance.h>
|
||||
#include <vintf/HalManifest.h>
|
||||
#include <vintf/VintfObject.h>
|
||||
|
@ -40,12 +41,6 @@ namespace lshal {
|
|||
|
||||
class Lshal;
|
||||
|
||||
struct PidInfo {
|
||||
std::map<uint64_t, Pids> refPids; // pids that are referenced
|
||||
uint32_t threadUsage; // number of threads in use
|
||||
uint32_t threadCount; // number of threads total
|
||||
};
|
||||
|
||||
enum class HalType {
|
||||
BINDERIZED_SERVICES = 0,
|
||||
PASSTHROUGH_CLIENTS,
|
||||
|
@ -110,9 +105,9 @@ protected:
|
|||
// Get relevant information for a PID by parsing files under
|
||||
// /dev/binderfs/binder_logs or /d/binder.
|
||||
// It is a virtual member function so that it can be mocked.
|
||||
virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
|
||||
virtual bool getPidInfo(pid_t serverPid, BinderPidInfo *info) const;
|
||||
// Retrieve from mCachedPidInfos and call getPidInfo if necessary.
|
||||
const PidInfo* getPidInfoCached(pid_t serverPid);
|
||||
const BinderPidInfo* getPidInfoCached(pid_t serverPid);
|
||||
|
||||
void dumpTable(const NullableOStream<std::ostream>& out) const;
|
||||
void dumpVintf(const NullableOStream<std::ostream>& out) const;
|
||||
|
@ -191,7 +186,7 @@ protected:
|
|||
std::map<pid_t, std::string> mCmdlines;
|
||||
|
||||
// Cache for getPidInfo.
|
||||
std::map<pid_t, PidInfo> mCachedPidInfos;
|
||||
std::map<pid_t, BinderPidInfo> mCachedPidInfos;
|
||||
|
||||
// Cache for getPartition.
|
||||
std::map<pid_t, Partition> mPartitions;
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace android {
|
|||
namespace lshal {
|
||||
|
||||
using android::procpartition::Partition;
|
||||
using Pids = std::vector<int32_t>;
|
||||
using Pids = std::vector<pid_t>;
|
||||
|
||||
enum class TableColumnType : unsigned int {
|
||||
INTERFACE_NAME = 0,
|
||||
|
|
|
@ -233,12 +233,12 @@ public:
|
|||
return ListCommand::dumpVintf(out);
|
||||
}
|
||||
void internalPostprocess() { ListCommand::postprocess(); }
|
||||
const PidInfo* getPidInfoCached(pid_t serverPid) {
|
||||
const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
|
||||
return ListCommand::getPidInfoCached(serverPid);
|
||||
}
|
||||
|
||||
MOCK_METHOD0(postprocess, void());
|
||||
MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
|
||||
MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
|
||||
MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
|
||||
MOCK_METHOD1(getPartition, Partition(pid_t));
|
||||
|
||||
|
@ -299,8 +299,8 @@ static uint64_t getPtr(pid_t serverId) { return 10000 + serverId; }
|
|||
static std::vector<pid_t> getClients(pid_t serverId) {
|
||||
return {serverId + 1, serverId + 3};
|
||||
}
|
||||
static PidInfo getPidInfoFromId(pid_t serverId) {
|
||||
PidInfo info;
|
||||
static BinderPidInfo getPidInfoFromId(pid_t serverId) {
|
||||
BinderPidInfo info;
|
||||
info.refPids[getPtr(serverId)] = getClients(serverId);
|
||||
info.threadUsage = 10 + serverId;
|
||||
info.threadCount = 20 + serverId;
|
||||
|
@ -363,7 +363,7 @@ public:
|
|||
void initMockList() {
|
||||
mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
|
||||
ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
|
||||
[](pid_t serverPid, PidInfo* info) {
|
||||
[](pid_t serverPid, BinderPidInfo* info) {
|
||||
*info = getPidInfoFromId(serverPid);
|
||||
return true;
|
||||
}));
|
||||
|
|
28
libs/binderdebug/Android.bp
Normal file
28
libs/binderdebug/Android.bp
Normal file
|
@ -0,0 +1,28 @@
|
|||
// Copyright (C) 2020 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 {
|
||||
name: "libbinderdebug",
|
||||
vendor_available: true,
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder",
|
||||
],
|
||||
srcs: [
|
||||
"BinderDebug.cpp",
|
||||
],
|
||||
export_include_dirs: [
|
||||
"include",
|
||||
],
|
||||
}
|
119
libs/binderdebug/BinderDebug.cpp
Normal file
119
libs/binderdebug/BinderDebug.cpp
Normal file
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <android-base/parseint.h>
|
||||
#include <android-base/strings.h>
|
||||
#include <binder/Binder.h>
|
||||
#include <sys/types.h>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
|
||||
#include <binderdebug/BinderDebug.h>
|
||||
|
||||
namespace android {
|
||||
|
||||
static std::string contextToString(BinderDebugContext context) {
|
||||
switch (context) {
|
||||
case BinderDebugContext::BINDER:
|
||||
return "binder";
|
||||
case BinderDebugContext::HWBINDER:
|
||||
return "hwbinder";
|
||||
case BinderDebugContext::VNDBINDER:
|
||||
return "vndbinder";
|
||||
default:
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
|
||||
static status_t scanBinderContext(pid_t pid, const std::string& contextName,
|
||||
std::function<void(const std::string&)> eachLine) {
|
||||
std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
|
||||
if (!ifs.is_open()) {
|
||||
ifs.open("/d/binder/proc/" + std::to_string(pid));
|
||||
if (!ifs.is_open()) {
|
||||
return -errno;
|
||||
}
|
||||
}
|
||||
static const std::regex kContextLine("^context (\\w+)$");
|
||||
|
||||
bool isDesiredContext = false;
|
||||
std::string line;
|
||||
std::smatch match;
|
||||
while (getline(ifs, line)) {
|
||||
if (std::regex_search(line, match, kContextLine)) {
|
||||
isDesiredContext = match.str(1) == contextName;
|
||||
continue;
|
||||
}
|
||||
if (!isDesiredContext) {
|
||||
continue;
|
||||
}
|
||||
eachLine(line);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
|
||||
std::smatch match;
|
||||
static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
|
||||
static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
|
||||
std::string contextStr = contextToString(context);
|
||||
status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
|
||||
if (std::regex_search(line, match, kReferencePrefix)) {
|
||||
const std::string& ptrString = "0x" + match.str(2); // use number after c
|
||||
uint64_t ptr;
|
||||
if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
|
||||
// Should not reach here, but just be tolerant.
|
||||
return;
|
||||
}
|
||||
const std::string proc = " proc ";
|
||||
auto pos = line.rfind(proc);
|
||||
if (pos != std::string::npos) {
|
||||
for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
|
||||
int32_t pid;
|
||||
if (!::android::base::ParseInt(pidStr, &pid)) {
|
||||
return;
|
||||
}
|
||||
pidInfo->refPids[ptr].push_back(pid);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if (std::regex_search(line, match, kThreadPrefix)) {
|
||||
// "1" is waiting in binder driver
|
||||
// "2" is poll. It's impossible to tell if these are in use.
|
||||
// and HIDL default code doesn't use it.
|
||||
bool isInUse = match.str(1) != "1";
|
||||
// "0" is a thread that has called into binder
|
||||
// "1" is looper thread
|
||||
// "2" is main looper thread
|
||||
bool isBinderThread = match.str(2) != "0";
|
||||
if (!isBinderThread) {
|
||||
return;
|
||||
}
|
||||
if (isInUse) {
|
||||
pidInfo->threadUsage++;
|
||||
}
|
||||
|
||||
pidInfo->threadCount++;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace android
|
7
libs/binderdebug/TEST_MAPPING
Normal file
7
libs/binderdebug/TEST_MAPPING
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"presubmit": [
|
||||
{
|
||||
"name": "libbinderdebug_test"
|
||||
}
|
||||
]
|
||||
}
|
37
libs/binderdebug/include/binderdebug/BinderDebug.h
Normal file
37
libs/binderdebug/include/binderdebug/BinderDebug.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <map>
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
|
||||
struct BinderPidInfo {
|
||||
std::map<uint64_t, std::vector<pid_t>> refPids; // cookie -> processes which hold binder
|
||||
uint32_t threadUsage; // number of threads in use
|
||||
uint32_t threadCount; // number of threads total
|
||||
};
|
||||
|
||||
enum class BinderDebugContext {
|
||||
BINDER,
|
||||
HWBINDER,
|
||||
VNDBINDER,
|
||||
};
|
||||
|
||||
status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
|
||||
|
||||
} // namespace android
|
30
libs/binderdebug/tests/Android.bp
Normal file
30
libs/binderdebug/tests/Android.bp
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright (C) 2020 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_test {
|
||||
name: "libbinderdebug_test",
|
||||
test_suites: ["general-tests"],
|
||||
srcs: [
|
||||
"binderdebug_test.cpp",
|
||||
"android/binderdebug/test/IControl.aidl",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"libbinder",
|
||||
"libutils",
|
||||
],
|
||||
static_libs: ["libbinderdebug"],
|
||||
cflags: ["-Wall", "-Werror"],
|
||||
require_root: true,
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.
|
||||
*/
|
||||
|
||||
package android.binderdebug.test;
|
||||
|
||||
interface IControl {
|
||||
// Notifies the service to continue execution
|
||||
void Continue();
|
||||
}
|
90
libs/binderdebug/tests/binderdebug_test.cpp
Normal file
90
libs/binderdebug/tests/binderdebug_test.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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 <binder/Binder.h>
|
||||
#include <binder/IServiceManager.h>
|
||||
#include <binder/ProcessState.h>
|
||||
#include <binder/IPCThreadState.h>
|
||||
#include <binderdebug/BinderDebug.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <semaphore.h>
|
||||
#include <thread>
|
||||
|
||||
#include <android/binderdebug/test/BnControl.h>
|
||||
#include <android/binderdebug/test/IControl.h>
|
||||
|
||||
namespace android {
|
||||
namespace binderdebug {
|
||||
namespace test {
|
||||
|
||||
class Control : public BnControl {
|
||||
public:
|
||||
Control() {sem_init(&s, 1, 0);};
|
||||
::android::binder::Status Continue() override;
|
||||
sem_t s;
|
||||
};
|
||||
|
||||
::android::binder::Status Control::Continue() {
|
||||
IPCThreadState::self()->flushCommands();
|
||||
sem_post(&s);
|
||||
return binder::Status::ok();
|
||||
}
|
||||
|
||||
TEST(BinderDebugTests, BinderPid) {
|
||||
BinderPidInfo pidInfo;
|
||||
const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
|
||||
ASSERT_EQ(status, OK);
|
||||
// There should be one referenced PID for servicemanager
|
||||
EXPECT_TRUE(!pidInfo.refPids.empty());
|
||||
}
|
||||
|
||||
TEST(BinderDebugTests, BinderThreads) {
|
||||
BinderPidInfo pidInfo;
|
||||
const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
|
||||
ASSERT_EQ(status, OK);
|
||||
EXPECT_TRUE(pidInfo.threadUsage <= pidInfo.threadCount);
|
||||
// The second looper thread can sometimes take longer to spawn.
|
||||
EXPECT_GE(pidInfo.threadCount, 1);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
// Create a child/client process to call into the main process so we can ensure
|
||||
// looper thread has been registered before attempting to get the BinderPidInfo
|
||||
pid_t pid = fork();
|
||||
if (pid == 0) {
|
||||
sp<IBinder> binder = android::defaultServiceManager()->getService(String16("binderdebug"));
|
||||
sp<IControl> service;
|
||||
if (binder != nullptr) {
|
||||
service = android::interface_cast<IControl>(binder);
|
||||
}
|
||||
service->Continue();
|
||||
exit(0);
|
||||
}
|
||||
sp<Control> iface = new Control;
|
||||
android::defaultServiceManager()->addService(String16("binderdebug"), iface);
|
||||
android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
|
||||
ProcessState::self()->startThreadPool();
|
||||
sem_wait(&iface->s);
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
} // extern "C"
|
||||
} // namespace test
|
||||
} // namespace binderdebug
|
||||
} // namespace android
|
Loading…
Reference in a new issue