blob: 6c9c394634f08059867b8cbedcfeb58a24d08e70 [file] [log] [blame]
/*
* Copyright 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 "ProcPidStat.h"
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <inttypes.h>
#include <algorithm>
#include <string>
#include "ProcPidDir.h"
#include "gmock/gmock.h"
namespace android {
namespace automotive {
namespace watchdog {
using android::base::StringAppendF;
using android::base::StringPrintf;
using testing::populateProcPidDir;
namespace {
std::string toString(const PidStat& stat) {
return StringPrintf("PID: %" PRIu32 ", PPID: %" PRIu32 ", Comm: %s, State: %s, "
"Major page faults: %" PRIu64 ", Num threads: %" PRIu32
", Start time: %" PRIu64,
stat.pid, stat.ppid, stat.comm.c_str(), stat.state.c_str(),
stat.majorFaults, stat.numThreads, stat.startTime);
}
std::string toString(const ProcessStats& stats) {
std::string buffer;
StringAppendF(&buffer, "Tgid: %" PRIi64 ", UID: %" PRIi64 ", %s\n", stats.tgid, stats.uid,
toString(stats.process).c_str());
StringAppendF(&buffer, "\tThread stats:\n");
for (const auto& it : stats.threads) {
StringAppendF(&buffer, "\t\t%s\n", toString(it.second).c_str());
}
StringAppendF(&buffer, "\n");
return buffer;
}
std::string toString(const std::vector<ProcessStats>& stats) {
std::string buffer;
StringAppendF(&buffer, "Number of processes: %d\n", static_cast<int>(stats.size()));
for (const auto& it : stats) {
StringAppendF(&buffer, "%s", toString(it).c_str());
}
return buffer;
}
bool isEqual(const PidStat& lhs, const PidStat& rhs) {
return lhs.pid == rhs.pid && lhs.comm == rhs.comm && lhs.state == rhs.state &&
lhs.ppid == rhs.ppid && lhs.majorFaults == rhs.majorFaults &&
lhs.numThreads == rhs.numThreads && lhs.startTime == rhs.startTime;
}
bool isEqual(std::vector<ProcessStats>* lhs, std::vector<ProcessStats>* rhs) {
if (lhs->size() != rhs->size()) {
return false;
}
std::sort(lhs->begin(), lhs->end(), [&](const ProcessStats& l, const ProcessStats& r) -> bool {
return l.process.pid < r.process.pid;
});
std::sort(rhs->begin(), rhs->end(), [&](const ProcessStats& l, const ProcessStats& r) -> bool {
return l.process.pid < r.process.pid;
});
return std::equal(lhs->begin(), lhs->end(), rhs->begin(),
[&](const ProcessStats& l, const ProcessStats& r) -> bool {
if (l.tgid != r.tgid || l.uid != r.uid ||
!isEqual(l.process, r.process) ||
l.threads.size() != r.threads.size()) {
return false;
}
for (const auto& lIt : l.threads) {
const auto& rIt = r.threads.find(lIt.first);
if (rIt == r.threads.end()) {
return false;
}
if (!isEqual(lIt.second, rIt->second)) {
return false;
}
}
return true;
});
}
} // namespace
TEST(ProcPidStatTest, TestValidStatFiles) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1, 453}},
{1000, {1000, 1100}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 2 0 0\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 1000\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
{1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 0\n"},
{453, "453 (init) S 0 0 0 0 0 0 0 0 20 0 0 0 0 0 0 0 2 0 275\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 2 0 1000\n"},
{1100, "1100 (system_server) S 1 0 0 0 0 0 0 0 350 0 0 0 0 0 0 0 2 0 1200\n"},
};
std::vector<ProcessStats> expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "init", "S", 0, 220, 2, 0},
.threads =
{
{1, {1, "init", "S", 0, 200, 2, 0}},
{453, {453, "init", "S", 0, 20, 2, 275}},
},
},
{
.tgid = 1000,
.uid = 10001234,
.process = {1000, "system_server", "R", 1, 600, 2, 1000},
.threads =
{
{1000, {1000, "system_server", "R", 1, 250, 2, 1000}},
{1100, {1100, "system_server", "S", 1, 350, 2, 1200}},
},
},
};
TemporaryDir firstSnapshot;
auto ret = populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(firstSnapshot.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << firstSnapshot.path << "` are inaccessible";
auto actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value())) << "First snapshot doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
pidToTids = {
{1, {1, 453}}, {1000, {1000, 1400}}, // TID 1100 terminated and 1400 instantiated.
};
perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 920 0 0 0 0 0 0 0 2 0 0\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 1550 0 0 0 0 0 0 0 2 0 1000\n"},
};
perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 0\n"},
{453, "453 (init) S 0 0 0 0 0 0 0 0 320 0 0 0 0 0 0 0 2 0 275\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 2 0 1000\n"},
// TID 1100 hits +400 major page faults before terminating. This is counted against
// PID 1000's perProcessStat.
{1400, "1400 (system_server) S 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 8977476\n"},
};
expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "init", "S", 0, 700, 2, 0},
.threads =
{
{1, {1, "init", "S", 0, 400, 2, 0}},
{453, {453, "init", "S", 0, 300, 2, 275}},
},
},
{
.tgid = 1000,
.uid = 10001234,
.process = {1000, "system_server", "R", 1, 950, 2, 1000},
.threads =
{
{1000, {1000, "system_server", "R", 1, 350, 2, 1000}},
{1400, {1400, "system_server", "S", 1, 200, 2, 8977476}},
},
},
};
TemporaryDir secondSnapshot;
ret = populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
procPidStat.mPath = secondSnapshot.path;
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << secondSnapshot.path << "` are inaccessible";
actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value()))
<< "Second snapshot doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
}
TEST(ProcPidStatTest, TestHandlesProcessTerminationBetweenScanningAndParsing) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1}},
{100, {100}}, // Process terminates after scanning PID directory.
{1000, {1000}}, // Process terminates after reading stat file.
{2000, {2000}}, // Process terminates after scanning task directory.
{3000, {3000, 3300}}, // TID 3300 terminates after scanning task directory.
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 0 0 0 0 0 0 1 0 0\n"},
// Process 100 terminated.
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 0 0 0 0 0 0 1 0 1000\n"},
{2000, "2000 (logd) R 1 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 1 0 4567\n"},
{3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 10300 0 0 0 0 0 0 0 2 0 67890\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
// Process 1000 terminated.
{2000, "Pid:\t2000\nTgid:\t2000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
{3000, "Pid:\t3000\nTgid:\t3000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
// Process 2000 terminated.
{3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 2400 0 0 0 0 0 0 0 2 0 67890\n"},
// TID 3300 terminated.
};
std::vector<ProcessStats> expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "init", "S", 0, 220, 1, 0},
.threads = {{1, {1, "init", "S", 0, 200, 1, 0}}},
},
{
.tgid = -1,
.uid = -1,
.process = {1000, "system_server", "R", 1, 600, 1, 1000},
// Stats common between process and main-thread are copied when
// main-thread stats are not available.
.threads = {{1000, {1000, "system_server", "R", 1, 0, 1, 1000}}},
},
{
.tgid = 2000,
.uid = 10001234,
.process = {2000, "logd", "R", 1, 1200, 1, 4567},
.threads = {{2000, {2000, "logd", "R", 1, 0, 1, 4567}}},
},
{
.tgid = 3000,
.uid = 10001234,
.process = {3000, "disk I/O", "R", 1, 10300, 2, 67890},
.threads = {{3000, {3000, "disk I/O", "R", 1, 2400, 2, 67890}}},
},
};
TemporaryDir procDir;
const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(procDir.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << procDir.path << "` are inaccessible";
auto actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value()))
<< "Proc pid contents doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
}
TEST(ProcPidStatTest, TestHandlesPidTidReuse) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1, 367, 453, 589}},
{1000, {1000}},
{2345, {2345}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 1200 0 0 0 0 0 0 0 4 0 0\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
{2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
{1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
{2345, "Pid:\t2345\nTgid:\t2345\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 4 0 0\n"},
{367, "367 (init) S 0 0 0 0 0 0 0 0 400 0 0 0 0 0 0 0 4 0 100\n"},
{453, "453 (init) S 0 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 4 0 275\n"},
{589, "589 (init) S 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 4 0 600\n"},
{1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 0 0 0 0 0 0 1 0 1000\n"},
{2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 0 0 0 0 0 0 1 0 456\n"},
};
std::vector<ProcessStats> expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "init", "S", 0, 1200, 4, 0},
.threads =
{
{1, {1, "init", "S", 0, 200, 4, 0}},
{367, {367, "init", "S", 0, 400, 4, 100}},
{453, {453, "init", "S", 0, 100, 4, 275}},
{589, {589, "init", "S", 0, 500, 4, 600}},
},
},
{
.tgid = 1000,
.uid = 10001234,
.process = {1000, "system_server", "R", 1, 250, 1, 1000},
.threads = {{1000, {1000, "system_server", "R", 1, 250, 1, 1000}}},
},
{
.tgid = 2345,
.uid = 10001234,
.process = {2345, "logd", "R", 1, 54354, 1, 456},
.threads = {{2345, {2345, "logd", "R", 1, 54354, 1, 456}}},
},
};
TemporaryDir firstSnapshot;
auto ret = populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(firstSnapshot.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << firstSnapshot.path << "` are inaccessible";
auto actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value())) << "First snapshot doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
pidToTids = {
{1, {1, 589}}, // TID 589 reused by the same process.
{367, {367, 2000}}, // TID 367 reused as a PID. PID 2000 reused as a TID.
// PID 1000 reused as a new PID. TID 453 reused by a different PID.
{1000, {1000, 453}},
};
perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 0\n"},
{367, "367 (system_server) R 1 0 0 0 0 0 0 0 100 0 0 0 0 0 0 0 2 0 3450\n"},
{1000, "1000 (logd) R 1 0 0 0 0 0 0 0 2000 0 0 0 0 0 0 0 2 0 4650\n"},
};
perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
{367, "Pid:\t367\nTgid:\t367\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
{1000, "Pid:\t1000\nTgid:\t1000\nUid:\t10001234\t10001234\t10001234\t10001234\n"},
};
perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 500 0 0 0 0 0 0 0 2 0 0\n"},
{589, "589 (init) S 0 0 0 0 0 0 0 0 300 0 0 0 0 0 0 0 2 0 2345\n"},
{367, "367 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3450\n"},
{2000, "2000 (system_server) R 1 0 0 0 0 0 0 0 50 0 0 0 0 0 0 0 2 0 3670\n"},
{1000, "1000 (logd) R 1 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 4650\n"},
{453, "453 (logd) D 1 0 0 0 0 0 0 0 1800 0 0 0 0 0 0 0 2 0 4770\n"},
};
expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "init", "S", 0, 600, 2, 0},
.threads =
{
{1, {1, "init", "S", 0, 300, 2, 0}},
{589, {589, "init", "S", 0, 300, 2, 2345}},
},
},
{
.tgid = 367,
.uid = 10001234,
.process = {367, "system_server", "R", 1, 100, 2, 3450},
.threads =
{
{367, {367, "system_server", "R", 1, 50, 2, 3450}},
{2000, {2000, "system_server", "R", 1, 50, 2, 3670}},
},
},
{
.tgid = 1000,
.uid = 10001234,
.process = {1000, "logd", "R", 1, 2000, 2, 4650},
.threads =
{
{1000, {1000, "logd", "R", 1, 200, 2, 4650}},
{453, {453, "logd", "D", 1, 1800, 2, 4770}},
},
},
};
TemporaryDir secondSnapshot;
ret = populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
procPidStat.mPath = secondSnapshot.path;
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << secondSnapshot.path << "` are inaccessible";
actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value()))
<< "Second snapshot doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
}
TEST(ProcPidStatTest, TestErrorOnCorruptedProcessStatFile) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
TemporaryDir procDir;
const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(procDir.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << procDir.path << "` are inaccessible";
const auto& actual = procPidStat.collect();
ASSERT_FALSE(actual) << "No error returned for invalid process stat file";
}
TEST(ProcPidStatTest, TestErrorOnCorruptedProcessStatusFile) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nCORRUPTED DATA\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
TemporaryDir procDir;
const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(procDir.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << procDir.path << "` are inaccessible";
const auto& actual = procPidStat.collect();
ASSERT_FALSE(actual) << "No error returned for invalid process status file";
}
TEST(ProcPidStatTest, TestErrorOnCorruptedThreadStatFile) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
};
TemporaryDir procDir;
const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(procDir.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << procDir.path << "` are inaccessible";
const auto& actual = procPidStat.collect();
ASSERT_FALSE(actual) << "No error returned for invalid thread stat file";
}
TEST(ProcPidStatTest, TestHandlesSpaceInCommName) {
std::unordered_map<uint32_t, std::vector<uint32_t>> pidToTids = {
{1, {1}},
};
std::unordered_map<uint32_t, std::string> perProcessStat = {
{1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
std::unordered_map<uint32_t, std::string> perProcessStatus = {
{1, "Pid:\t1\nTgid:\t1\nUid:\t0\t0\t0\t0\n"},
};
std::unordered_map<uint32_t, std::string> perThreadStat = {
{1, "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 0\n"},
};
std::vector<ProcessStats> expected = {
{
.tgid = 1,
.uid = 0,
.process = {1, "random process name with space", "S", 0, 200, 1, 0},
.threads = {{1, {1, "random process name with space", "S", 0, 200, 1, 0}}},
},
};
TemporaryDir procDir;
const auto& ret = populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
perThreadStat);
ASSERT_TRUE(ret) << "Failed to populate proc pid dir: " << ret.error();
ProcPidStat procPidStat(procDir.path);
ASSERT_TRUE(procPidStat.enabled())
<< "Files under the path `" << procDir.path << "` are inaccessible";
auto actual = procPidStat.collect();
ASSERT_TRUE(actual) << "Failed to collect proc pid stat: " << actual.error();
EXPECT_TRUE(isEqual(&expected, &actual.value()))
<< "Proc pid contents doesn't match.\nExpected:\n"
<< toString(expected) << "\nActual:\n"
<< toString(*actual);
}
TEST(ProcPidStatTest, TestProcPidStatContentsFromDevice) {
// TODO(b/148486340): Enable the test after appropriate SELinux privileges are available to
// read the proc file.
/*ProcPidStat procPidStat;
ASSERT_TRUE(procPidStat.enabled()) << "/proc/[pid]/.* files are inaccessible";
const auto& processStats = procPidStat.collect();
ASSERT_TRUE(processStats) << "Failed to collect proc pid stat: " << processStats.error();
// The below check should pass because there should be at least one process.
EXPECT_GT(processStats->size(), 0);*/
}
} // namespace watchdog
} // namespace automotive
} // namespace android