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