Skip to content

Commit 6debdb1

Browse files
committed
Create android Users table probes
Change-Id: I9fe139e224914f63ff034c2ca7aea2b2503130ea
1 parent a614bf4 commit 6debdb1

File tree

8 files changed

+451
-0
lines changed

8 files changed

+451
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
syntax = "proto2";
18+
19+
package perfetto.protos;
20+
21+
// Data source that lists details (such as version code) about users on an
22+
// Android device.
23+
message UserListConfig {
24+
// If not empty, emit info about only the following list of user types
25+
// (exact match, no regex). Otherwise, emit info about all users.
26+
repeated string user_type_filter = 1;
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
syntax = "proto2";
18+
package perfetto.protos;
19+
20+
message UserList {
21+
message UserInfo {
22+
optional string type = 1;
23+
optional uint64 uid = 2;
24+
}
25+
26+
repeated UserInfo users = 1;
27+
28+
// At least one error occurred parsing the user.list.
29+
optional bool parse_error = 2;
30+
31+
// Failed to open / read user.list.
32+
optional bool read_error = 3;
33+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Copyright (C) 2025 The Android Open Source Project
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
import("../../../../gn/test.gni")
16+
17+
source_set("user_list_parser") {
18+
deps = [
19+
"../../../../gn:default_deps",
20+
"../../../base",
21+
]
22+
sources = [
23+
"user_list_parser.cc",
24+
"user_list_parser.h",
25+
]
26+
}
27+
28+
source_set("user_list") {
29+
public_deps = [ "../../../tracing/core" ]
30+
deps = [
31+
":user_list_parser",
32+
"..:data_source",
33+
"../../../../gn:default_deps",
34+
"../../../../include/perfetto/ext/traced",
35+
"../../../../protos/perfetto/common:zero",
36+
"../../../../protos/perfetto/config/android:zero",
37+
"../../../../protos/perfetto/trace:zero",
38+
"../../../../protos/perfetto/trace/android:zero",
39+
"../../../base",
40+
]
41+
sources = [
42+
"user_list_data_source.cc",
43+
"user_list_data_source.h",
44+
]
45+
}
46+
47+
perfetto_unittest_source_set("unittests") {
48+
testonly = true
49+
deps = [
50+
":user_list",
51+
":user_list_parser",
52+
"../../../../gn:default_deps",
53+
"../../../../gn:gtest_and_gmock",
54+
"../../../../protos/perfetto/trace/android:cpp",
55+
"../../../../protos/perfetto/trace/android:zero",
56+
"../../../../src/base:test_support",
57+
"../../../../src/tracing/test:test_support",
58+
]
59+
sources = [ "user_list_unittest.cc" ]
60+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "src/traced/probes/user_list/user_list_data_source.h"
18+
19+
#include "perfetto/ext/base/scoped_file.h"
20+
#include "perfetto/ext/base/string_splitter.h"
21+
22+
#include "perfetto/ext/tracing/core/trace_writer.h"
23+
#include "protos/perfetto/trace/trace_packet.pbzero.h"
24+
25+
#include "src/traced/probes/user_list/user_list_parser.h"
26+
27+
using perfetto::protos::pbzero::UserListConfig;
28+
29+
namespace perfetto {
30+
31+
// static
32+
const ProbesDataSource::Descriptor UserListDataSource::descriptor = {
33+
/*type*/ "android.user_list",
34+
/*flags*/ Descriptor::kFlagsNone,
35+
/*fill_descriptor_func*/ nullptr,
36+
};
37+
38+
bool ParseUserListStream(protos::pbzero::UserList* user_list_packet,
39+
const base::ScopedFstream& fs,
40+
const std::set<std::string>& user_type_filter) {
41+
bool parsed_fully = true;
42+
char line[2048];
43+
while (fgets(line, sizeof(line), *fs) != nullptr) {
44+
User pkg_struct;
45+
if (!ReadUserListLine(line, &pkg_struct)) {
46+
parsed_fully = false;
47+
continue;
48+
}
49+
if (!user_type_filter.empty() &&
50+
user_type_filter.count(pkg_struct.type) == 0) {
51+
continue;
52+
}
53+
auto* user = user_list_packet->add_users();
54+
user->set_type(pkg_struct.type.c_str(), pkg_struct.type.size());
55+
user->set_uid(pkg_struct.uid);
56+
}
57+
return parsed_fully;
58+
}
59+
60+
UserListDataSource::UserListDataSource(const DataSourceConfig& ds_config,
61+
TracingSessionID session_id,
62+
std::unique_ptr<TraceWriter> writer)
63+
: ProbesDataSource(session_id, &descriptor), writer_(std::move(writer)) {
64+
UserListConfig::Decoder cfg(ds_config.user_list_config_raw());
65+
for (auto type = cfg.user_type_filter(); type; ++type) {
66+
user_type_filter_.emplace((*type).ToStdString());
67+
}
68+
}
69+
70+
void UserListDataSource::Start() {
71+
base::ScopedFstream fs(fopen("/data/system/users/user.list", "r"));
72+
auto trace_packet = writer_->NewTracePacket();
73+
auto* user_list_packet = trace_packet->set_user_list();
74+
if (!fs) {
75+
PERFETTO_ELOG("Failed to open user.list");
76+
user_list_packet->set_read_error(true);
77+
trace_packet->Finalize();
78+
writer_->Flush();
79+
return;
80+
}
81+
82+
bool parsed_fully =
83+
ParseUserListStream(user_list_packet, fs, user_type_filter_);
84+
if (!parsed_fully)
85+
user_list_packet->set_parse_error(true);
86+
87+
if (ferror(*fs))
88+
user_list_packet->set_read_error(true);
89+
90+
trace_packet->Finalize();
91+
writer_->Flush();
92+
}
93+
94+
void UserListDataSource::Flush(FlushRequestID, std::function<void()> callback) {
95+
// Flush is no-op. We flush after the first write.
96+
callback();
97+
}
98+
99+
UserListDataSource::~UserListDataSource() = default;
100+
101+
} // namespace perfetto
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef SRC_TRACED_PROBES_USER_LIST_USER_LIST_DATA_SOURCE_H_
18+
#define SRC_TRACED_PROBES_USER_LIST_USER_LIST_DATA_SOURCE_H_
19+
20+
#include <functional>
21+
#include <memory>
22+
#include <set>
23+
24+
#include "perfetto/base/task_runner.h"
25+
#include "perfetto/ext/base/scoped_file.h"
26+
27+
#include "perfetto/ext/tracing/core/basic_types.h"
28+
#include "perfetto/tracing/core/data_source_config.h"
29+
#include "protos/perfetto/config/android/user_list_config.pbzero.h"
30+
#include "protos/perfetto/trace/android/user_list.pbzero.h"
31+
32+
#include "src/traced/probes/probes_data_source.h"
33+
34+
namespace perfetto {
35+
36+
class TraceWriter;
37+
38+
bool ParseUserListStream(protos::pbzero::UserList* user_list,
39+
const base::ScopedFstream& fs,
40+
const std::set<std::string>& user_type_filter);
41+
42+
class UserListDataSource : public ProbesDataSource {
43+
public:
44+
static const ProbesDataSource::Descriptor descriptor;
45+
46+
UserListDataSource(const DataSourceConfig& ds_config,
47+
TracingSessionID session_id,
48+
std::unique_ptr<TraceWriter> writer);
49+
// ProbesDataSource implementation.
50+
void Start() override;
51+
void Flush(FlushRequestID, std::function<void()> callback) override;
52+
53+
~UserListDataSource() override;
54+
55+
private:
56+
// If empty, include all user types. std::set over std::unordered_set as
57+
// this should be trivially small (or empty) in practice, and the latter uses
58+
// ever so slightly more memory.
59+
std::set<std::string> user_type_filter_;
60+
std::unique_ptr<TraceWriter> writer_;
61+
};
62+
63+
} // namespace perfetto
64+
65+
#endif // SRC_TRACED_PROBES_USER_LIST_USER_LIST_DATA_SOURCE_H_
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "src/traced/probes/user_list/user_list_parser.h"
18+
19+
#include <stdlib.h>
20+
21+
#include "perfetto/ext/base/scoped_file.h"
22+
#include "perfetto/ext/base/string_splitter.h"
23+
24+
namespace perfetto {
25+
26+
bool ReadUserListLine(char* line, User* user) {
27+
size_t idx = 0;
28+
for (base::StringSplitter ss(line, ' '); ss.Next();) {
29+
switch (idx) {
30+
case 0:
31+
user->type = std::string(ss.cur_token(), ss.cur_token_size());
32+
break;
33+
case 1: {
34+
char* end;
35+
long long uid = strtoll(ss.cur_token(), &end, 10);
36+
if ((*end != '\0' && *end != '\n') || *ss.cur_token() == '\0') {
37+
PERFETTO_ELOG("Failed to parse user.list uid.");
38+
return false;
39+
}
40+
user->uid = static_cast<uint64_t>(uid);
41+
break;
42+
}
43+
}
44+
++idx;
45+
}
46+
return true;
47+
}
48+
49+
} // namespace perfetto
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright (C) 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef SRC_TRACED_PROBES_USER_LIST_USER_LIST_PARSER_H_
18+
#define SRC_TRACED_PROBES_USER_LIST_USER_LIST_PARSER_H_
19+
20+
#include <cinttypes>
21+
#include <string>
22+
23+
namespace perfetto {
24+
25+
struct User {
26+
std::string type;
27+
uint64_t uid = 0;
28+
};
29+
30+
bool ReadUserListLine(char* line, User* user);
31+
} // namespace perfetto
32+
33+
#endif // SRC_TRACED_PROBES_USER_LIST_USER_LIST_PARSER_H_

0 commit comments

Comments
 (0)