Skip to content

Create android Users table #1246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions Android.bp

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,8 @@ perfetto_cc_library(
":src_traced_probes_sys_stats_sys_stats",
":src_traced_probes_system_info_cpu_info_features_allowlist",
":src_traced_probes_system_info_system_info",
":src_traced_probes_user_list_user_list",
":src_traced_probes_user_list_user_list_parser",
":src_tracing_ipc_producer_producer",
],
}),
Expand Down Expand Up @@ -4235,6 +4237,24 @@ perfetto_filegroup(
],
)

# GN target: //src/traced/probes/user_list:user_list
perfetto_filegroup(
name = "src_traced_probes_user_list_user_list",
srcs = [
"src/traced/probes/user_list/user_list_data_source.cc",
"src/traced/probes/user_list/user_list_data_source.h",
],
)

# GN target: //src/traced/probes/user_list_user_list_parser
perfetto_filegroup(
name = "src_traced_probes_user_list_user_list_parser",
srcs = [
"src/traced/probes/user_list/user_list_parser.cc",
"src/traced/probes/user_list/user_list_parser.h",
],
)

# GN target: //src/traced/probes:data_source
perfetto_filegroup(
name = "src_traced_probes_data_source",
Expand Down Expand Up @@ -5215,6 +5235,7 @@ perfetto_proto_library(
"protos/perfetto/config/android/protolog_config.proto",
"protos/perfetto/config/android/surfaceflinger_layers_config.proto",
"protos/perfetto/config/android/surfaceflinger_transactions_config.proto",
"protos/perfetto/config/android/user_list_config.proto",
"protos/perfetto/config/android/windowmanager_config.proto",
],
visibility = [
Expand Down Expand Up @@ -6001,6 +6022,7 @@ perfetto_proto_library(
"protos/perfetto/trace/android/network_trace.proto",
"protos/perfetto/trace/android/packages_list.proto",
"protos/perfetto/trace/android/pixel_modem_events.proto",
"protos/perfetto/trace/android/user_list.proto",
],
visibility = [
PERFETTO_CONFIG.proto_library_visibility,
Expand Down
1 change: 1 addition & 0 deletions protos/perfetto/config/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ perfetto_proto_library("@TYPE@") {
"protolog_config.proto",
"surfaceflinger_layers_config.proto",
"surfaceflinger_transactions_config.proto",
"user_list_config.proto",
"windowmanager_config.proto",
]
}
27 changes: 27 additions & 0 deletions protos/perfetto/config/android/user_list_config.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright (C) 2025 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.
*/

syntax = "proto2";

package perfetto.protos;

// Data source that lists details (such as version code) about users on an
// Android device.
message UserListConfig {
// If not empty, emit info about only the following list of user types
// (exact match, no regex). Otherwise, emit info about all users.
repeated string user_name_filter = 1;
}
6 changes: 5 additions & 1 deletion protos/perfetto/config/data_source_config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import "protos/perfetto/config/android/pixel_modem_config.proto";
import "protos/perfetto/config/android/protolog_config.proto";
import "protos/perfetto/config/android/surfaceflinger_layers_config.proto";
import "protos/perfetto/config/android/surfaceflinger_transactions_config.proto";
import "protos/perfetto/config/android/user_list_config.proto";
import "protos/perfetto/config/android/windowmanager_config.proto";
import "protos/perfetto/config/chrome/chrome_config.proto";
import "protos/perfetto/config/chrome/v8_config.proto";
Expand All @@ -56,7 +57,7 @@ import "protos/perfetto/config/system_info/system_info.proto";
import "protos/perfetto/config/chrome/histogram_samples.proto";

// The configuration that is passed to each data source when starting tracing.
// Next id: 136
// Next id: 137
message DataSourceConfig {
enum SessionInitiator {
SESSION_INITIATOR_UNSPECIFIED = 0;
Expand Down Expand Up @@ -227,6 +228,9 @@ message DataSourceConfig {
// Data source name: android.app_wakelocks
optional AppWakelocksConfig app_wakelocks_config = 135 [lazy = true];

// Data source name: android.user_list
optional UserListConfig user_list_config = 136 [lazy = true];

// This is a fallback mechanism to send a free-form text config to the
// producer. In theory this should never be needed. All the code that
// is part of the platform (i.e. traced service) is supposed to *not* truncate
Expand Down
17 changes: 16 additions & 1 deletion protos/perfetto/config/perfetto_config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -3764,10 +3764,22 @@ message TrackEventConfig {

// End of protos/perfetto/config/track_event/track_event_config.proto

// Begin of protos/perfetto/config/android/user_list_config.proto

// Data source that lists details (such as version code) about users on an
// Android device.
message UserListConfig {
// If not empty, emit info about only the following list of user types
// (exact match, no regex). Otherwise, emit info about all users.
repeated string user_name_filter = 1;
}

// End of protos/perfetto/config/android/user_list_config.proto

// Begin of protos/perfetto/config/data_source_config.proto

// The configuration that is passed to each data source when starting tracing.
// Next id: 136
// Next id: 137
message DataSourceConfig {
enum SessionInitiator {
SESSION_INITIATOR_UNSPECIFIED = 0;
Expand Down Expand Up @@ -3938,6 +3950,9 @@ message DataSourceConfig {
// Data source name: android.app_wakelocks
optional AppWakelocksConfig app_wakelocks_config = 135 [lazy = true];

// Data source name: android.user_list
optional UserListConfig user_list_config = 136 [lazy = true];

// This is a fallback mechanism to send a free-form text config to the
// producer. In theory this should never be needed. All the code that
// is part of the platform (i.e. traced service) is supposed to *not* truncate
Expand Down
1 change: 1 addition & 0 deletions protos/perfetto/trace/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ perfetto_proto_library("@TYPE@") {
"network_trace.proto",
"packages_list.proto",
"pixel_modem_events.proto",
"user_list.proto",
]
}

Expand Down
34 changes: 34 additions & 0 deletions protos/perfetto/trace/android/user_list.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2025 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.
*/

syntax = "proto2";
package perfetto.protos;

message UserList {
message UserInfo {
optional string name = 1;
optional uint64 uid = 2;
}

repeated UserInfo users = 1;


// At least one error occurred parsing the user.list.
optional bool parse_error = 2;

// Failed to open / read user.list.
optional bool read_error = 3;
}
36 changes: 34 additions & 2 deletions protos/perfetto/trace/perfetto_trace.proto
Original file line number Diff line number Diff line change
Expand Up @@ -857,6 +857,14 @@ message SurfaceFlingerTransactionsConfig {

// End of protos/perfetto/config/android/surfaceflinger_transactions_config.proto

// Data source that lists details (such as version code) about users on an
// Android device.
message UserListConfig {
// If not empty, emit info about only the following list of user types
// (exact match, no regex). Otherwise, emit info about all users.
repeated string user_name_filter = 1;
}

// Begin of protos/perfetto/config/android/windowmanager_config.proto

// Custom configuration for the "android.windowmanager" data source.
Expand Down Expand Up @@ -3767,7 +3775,7 @@ message TrackEventConfig {
// Begin of protos/perfetto/config/data_source_config.proto

// The configuration that is passed to each data source when starting tracing.
// Next id: 136
// Next id: 137
message DataSourceConfig {
enum SessionInitiator {
SESSION_INITIATOR_UNSPECIFIED = 0;
Expand Down Expand Up @@ -3938,6 +3946,9 @@ message DataSourceConfig {
// Data source name: android.app_wakelocks
optional AppWakelocksConfig app_wakelocks_config = 135 [lazy = true];

// Data source name: android.user_list
optional UserListConfig user_list_config = 136 [lazy = true];

// This is a fallback mechanism to send a free-form text config to the
// producer. In theory this should never be needed. All the code that
// is part of the platform (i.e. traced service) is supposed to *not* truncate
Expand Down Expand Up @@ -6407,6 +6418,25 @@ message DisplayState {

// End of protos/perfetto/trace/android/surfaceflinger_transactions.proto

// Begin of protos/perfetto/trace/android/user_list.proto

message UserList {
message UserInfo {
optional string name = 1;
optional uint64 uid = 2;
}

repeated UserInfo users = 1;

// At least one error occurred parsing the user.list.
optional bool parse_error = 2;

// Failed to open / read users.list.
optional bool read_error = 3;
}

// End of protos/perfetto/trace/android/user_list.proto

// Begin of protos/perfetto/trace/android/winscope_extensions.proto

message WinscopeExtensions {
Expand Down Expand Up @@ -16051,7 +16081,7 @@ message UiState {
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
// Next id: 117.
// Next id: 118.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
Expand Down Expand Up @@ -16198,6 +16228,8 @@ message TracePacket {

AppWakelockBundle app_wakelock_bundle = 116;

UserList user_list = 117;

// This field is only used for testing.
// In previous versions of this proto this field had the id 268435455
// This caused many problems:
Expand Down
5 changes: 4 additions & 1 deletion protos/perfetto/trace/trace_packet.proto
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import "protos/perfetto/trace/android/protolog.proto";
import "protos/perfetto/trace/android/shell_transition.proto";
import "protos/perfetto/trace/android/surfaceflinger_layers.proto";
import "protos/perfetto/trace/android/surfaceflinger_transactions.proto";
import "protos/perfetto/trace/android/user_list.proto";
import "protos/perfetto/trace/android/winscope_extensions.proto";
import "protos/perfetto/trace/chrome/chrome_benchmark_metadata.proto";
import "protos/perfetto/trace/chrome/chrome_metadata.proto";
Expand Down Expand Up @@ -107,7 +108,7 @@ package perfetto.protos;
// See the [Buffers and Dataflow](/docs/concepts/buffers.md) doc for details.
//
// Next reserved id: 14 (up to 15).
// Next id: 117.
// Next id: 118.
message TracePacket {
// The timestamp of the TracePacket.
// By default this timestamps refers to the trace clock (CLOCK_BOOTTIME on
Expand Down Expand Up @@ -254,6 +255,8 @@ message TracePacket {

AppWakelockBundle app_wakelock_bundle = 116;

UserList user_list = 117;

// This field is only used for testing.
// In previous versions of this proto this field had the id 268435455
// This caused many problems:
Expand Down
29 changes: 29 additions & 0 deletions src/trace_processor/importers/proto/android_probes_module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include "protos/perfetto/common/android_energy_consumer_descriptor.pbzero.h"
#include "protos/perfetto/config/trace_config.pbzero.h"
#include "protos/perfetto/trace/android/packages_list.pbzero.h"
#include "protos/perfetto/trace/android/user_list.pbzero.h"
#include "protos/perfetto/trace/power/android_energy_estimation_breakdown.pbzero.h"
#include "protos/perfetto/trace/power/android_entity_state_residency.pbzero.h"
#include "protos/perfetto/trace/power/power_rails.pbzero.h"
Expand Down Expand Up @@ -137,6 +138,7 @@ AndroidProbesModule::AndroidProbesModule(TraceProcessorContext* context)
RegisterForField(TracePacket::kEntityStateResidencyFieldNumber, context);
RegisterForField(TracePacket::kAndroidLogFieldNumber, context);
RegisterForField(TracePacket::kPackagesListFieldNumber, context);
RegisterForField(TracePacket::kUserListFieldNumber, context);
RegisterForField(TracePacket::kAndroidGameInterventionListFieldNumber,
context);
RegisterForField(TracePacket::kInitialDisplayStateFieldNumber, context);
Expand All @@ -161,6 +163,9 @@ ModuleResult AndroidProbesModule::TokenizePacket(
if (field_id == TracePacket::kPackagesListFieldNumber) {
return ParseAndroidPackagesList(decoder.packages_list());
}
if (field_id == TracePacket::kUserListFieldNumber) {
return ParseAndroidUserList(decoder.user_list());
}
if (field_id == TracePacket::kEntityStateResidencyFieldNumber) {
ParseEntityStateDescriptor(decoder.entity_state_residency());
// Ignore so that we get a go at parsing any actual residency data that
Expand Down Expand Up @@ -350,6 +355,30 @@ ModuleResult AndroidProbesModule::ParseAndroidPackagesList(
return ModuleResult::Handled();
}


ModuleResult AndroidProbesModule::ParseAndroidUserList(
protozero::ConstBytes blob) {
protos::pbzero::UserList::Decoder usr_list(blob.data, blob.size);
context_->storage->SetStats(stats::user_list_has_read_errors,
usr_list.read_error());
context_->storage->SetStats(stats::user_list_has_parse_errors,
usr_list.parse_error());

AndroidProbesTracker* tracker = AndroidProbesTracker::GetOrCreate(context_);
for (auto it = usr_list.users(); it; ++it) {
protos::pbzero::UserList_UserInfo::Decoder usr(*it);
std::string usr_name = usr.name().ToStdString();
if (!tracker->ShouldInsertUser(usr_name)) {
continue;
}
context_->storage->mutable_user_list_table()->Insert(
{context_->storage->InternString(usr.name()),
static_cast<int64_t>(usr.uid())});
tracker->InsertedUser(std::move(usr_name));
}
return ModuleResult::Handled();
}

void AndroidProbesModule::ParseEntityStateDescriptor(
protozero::ConstBytes blob) {
protos::pbzero::EntityStateResidency::Decoder event(blob);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class AndroidProbesModule : public ProtoImporterModule {

ModuleResult ParseEnergyDescriptor(protozero::ConstBytes blob);
ModuleResult ParseAndroidPackagesList(protozero::ConstBytes blob);
ModuleResult ParseAndroidUserList(protozero::ConstBytes blob);
void ParseEntityStateDescriptor(protozero::ConstBytes blob);

private:
Expand Down
12 changes: 12 additions & 0 deletions src/trace_processor/importers/proto/android_probes_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ class AndroidProbesTracker : public Destructible {
seen_packages_.emplace(std::move(package_name));
}


// TODO: replace with uid
bool ShouldInsertUser(const std::string& user_name) const {
auto it = seen_users_.find(user_name);
return it == seen_users_.end();
}

void InsertedUser(std::string user_name) {
seen_users_.emplace(std::move(user_name));
}

std::optional<TrackId> GetPowerRailTrack(uint32_t index) {
if (index >= power_rail_tracks_.size())
return std::nullopt;
Expand Down Expand Up @@ -141,6 +152,7 @@ class AndroidProbesTracker : public Destructible {
private:
TraceStorage* storage_;
std::set<std::string> seen_packages_;
std::set<std::string> seen_users_;
std::vector<TrackId> power_rail_tracks_;
std::unordered_map<int32_t, EnergyConsumerSpecs> energy_consumer_descriptors_;
std::unordered_map<uint64_t, EntityStateDescriptor> entity_state_descriptors_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1148,3 +1148,5 @@ SELECT
field_type_name,
deobfuscated_field_name
FROM __intrinsic_heap_graph_reference;


2 changes: 2 additions & 0 deletions src/trace_processor/storage/stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ namespace perfetto::trace_processor::stats {
F(metatrace_overruns, kSingle, kError, kTrace, ""), \
F(packages_list_has_parse_errors, kSingle, kError, kTrace, ""), \
F(packages_list_has_read_errors, kSingle, kError, kTrace, ""), \
F(user_list_has_parse_errors, kSingle, kError, kTrace, ""), \
F(user_list_has_read_errors, kSingle, kError, kTrace, ""), \
F(game_intervention_has_parse_errors, kSingle, kError, kTrace, \
"One or more parsing errors occurred. This could result from " \
"unknown game more or intervention added to the file to be parsed."), \
Expand Down
Loading
Loading