1 /*
2 * Copyright (C) 2019 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/packages_list/packages_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/packages_list/packages_list_parser.h"
26
27 using perfetto::protos::pbzero::PackagesListConfig;
28
29 namespace perfetto {
30
31 // static
32 const ProbesDataSource::Descriptor PackagesListDataSource::descriptor = {
33 /*name*/ "android.packages_list",
34 /*flags*/ Descriptor::kFlagsNone,
35 /*fill_descriptor_func*/ nullptr,
36 };
37
ParsePackagesListStream(protos::pbzero::PackagesList * packages_list_packet,const base::ScopedFstream & fs,const std::set<std::string> & package_name_filter)38 bool ParsePackagesListStream(protos::pbzero::PackagesList* packages_list_packet,
39 const base::ScopedFstream& fs,
40 const std::set<std::string>& package_name_filter) {
41 bool parsed_fully = true;
42 char line[2048];
43 while (fgets(line, sizeof(line), *fs) != nullptr) {
44 Package pkg_struct;
45 if (!ReadPackagesListLine(line, &pkg_struct)) {
46 parsed_fully = false;
47 continue;
48 }
49 if (!package_name_filter.empty() &&
50 package_name_filter.count(pkg_struct.name) == 0) {
51 continue;
52 }
53 auto* package = packages_list_packet->add_packages();
54 package->set_name(pkg_struct.name.c_str(), pkg_struct.name.size());
55 package->set_uid(pkg_struct.uid);
56 package->set_debuggable(pkg_struct.debuggable);
57 package->set_profileable_from_shell(pkg_struct.profileable_from_shell);
58 package->set_version_code(pkg_struct.version_code);
59 }
60 return parsed_fully;
61 }
62
PackagesListDataSource(const DataSourceConfig & ds_config,TracingSessionID session_id,std::unique_ptr<TraceWriter> writer)63 PackagesListDataSource::PackagesListDataSource(
64 const DataSourceConfig& ds_config,
65 TracingSessionID session_id,
66 std::unique_ptr<TraceWriter> writer)
67 : ProbesDataSource(session_id, &descriptor), writer_(std::move(writer)) {
68 PackagesListConfig::Decoder cfg(ds_config.packages_list_config_raw());
69 for (auto name = cfg.package_name_filter(); name; ++name) {
70 package_name_filter_.emplace((*name).ToStdString());
71 }
72 }
73
Start()74 void PackagesListDataSource::Start() {
75 base::ScopedFstream fs(fopen("/data/system/packages.list", "r"));
76 auto trace_packet = writer_->NewTracePacket();
77 auto* packages_list_packet = trace_packet->set_packages_list();
78 if (!fs) {
79 PERFETTO_ELOG("Failed to open packages.list");
80 packages_list_packet->set_read_error(true);
81 trace_packet->Finalize();
82 writer_->Flush();
83 return;
84 }
85
86 bool parsed_fully =
87 ParsePackagesListStream(packages_list_packet, fs, package_name_filter_);
88 if (!parsed_fully)
89 packages_list_packet->set_parse_error(true);
90
91 if (ferror(*fs))
92 packages_list_packet->set_read_error(true);
93
94 trace_packet->Finalize();
95 writer_->Flush();
96 }
97
Flush(FlushRequestID,std::function<void ()> callback)98 void PackagesListDataSource::Flush(FlushRequestID,
99 std::function<void()> callback) {
100 // Flush is no-op. We flush after the first write.
101 callback();
102 }
103
104 PackagesListDataSource::~PackagesListDataSource() = default;
105
106 } // namespace perfetto
107