File: ui_hierarchy_data_collector.cc

package info (click to toggle)
chromium 138.0.7204.183-1~deb12u1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-proposed-updates
  • size: 6,080,960 kB
  • sloc: cpp: 34,937,079; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,954; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,811; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (158 lines) | stat: -rw-r--r-- 5,796 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/support_tool/ash/ui_hierarchy_data_collector.h"

#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "ash/public/cpp/debug_utils.h"
#include "base/check.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/scoped_refptr.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "chrome/browser/support_tool/data_collector.h"
#include "components/feedback/redaction_tool/pii_types.h"
#include "components/feedback/redaction_tool/redaction_tool.h"
#include "third_party/re2/src/re2/re2.h"

UiHierarchyDataCollector::UiHierarchyDataCollector() = default;
UiHierarchyDataCollector::~UiHierarchyDataCollector() = default;

namespace {

UIHierarchyData CollectUiHierarchyData() {
  std::ostringstream out;
  out << "UI Hierarchy: Windows\n";
  std::vector<std::string> window_titles =
      ash::debug::PrintWindowHierarchy(&out, /*scrub_data=*/false);

  out << "UI Hierarchy: Views\n";
  ash::debug::PrintViewHierarchy(&out);

  out << "UI Hierarchy: Layers\n";
  ash::debug::PrintLayerHierarchy(&out);

  return UIHierarchyData(window_titles, /*data=*/out.str());
}

}  // namespace

UIHierarchyData::UIHierarchyData(std::vector<std::string> window_titles,
                                 std::string data)
    : window_titles(std::move(window_titles)), data(std::move(data)) {}

UIHierarchyData::~UIHierarchyData() = default;

UIHierarchyData::UIHierarchyData(UIHierarchyData&& ui_hierarchy_data) = default;

bool UiHierarchyDataCollector::WriteOutputFile(
    std::string ui_hierarchy_data,
    base::FilePath target_directory,
    std::set<redaction::PIIType> pii_types_to_keep) {
  if (pii_types_to_keep.count(redaction::PIIType::kUIHierarchyWindowTitles) ==
      0) {
    ui_hierarchy_data = RemoveWindowTitles(ui_hierarchy_data);
  }
  return base::WriteFile(
      target_directory.Append(FILE_PATH_LITERAL("ui_hierarchy.txt")),
      ui_hierarchy_data);
}

std::string UiHierarchyDataCollector::RemoveWindowTitles(
    const std::string& ui_hierarchy_data) {
  // `ui_hierarchy_data` stores every component in a new line. Window titles are
  // stored in "title=<window title>\n" format in `ui_hierarchy_data`.
  re2::RE2 regex_pattern("(?s)(.*?)title=(?-s)(.+)\\n");
  std::string_view input(ui_hierarchy_data);

  // `regex_pattern` has two matching groups: first one is for the skipped input
  // that doesn't contain any window titles and second one is for the matched
  // window title.
  std::string_view skipped_part;
  std::string_view matched_window_title;
  std::string redacted;

  while (re2::RE2::Consume(&input, regex_pattern, &skipped_part,
                           &matched_window_title)) {
    redacted.append(skipped_part);
    redacted += "title=<REDACTED>\n";
  }
  // Append the rest of the input to `redacted`. Only the unmatched last part
  // will be present in the `input` as we're using Consume() function.
  redacted.append(input);
  return redacted;
}

std::string UiHierarchyDataCollector::GetName() const {
  return "UI Hierarchy";
}

std::string UiHierarchyDataCollector::GetDescription() const {
  return "Collects UI hiearchy data and exports the data into file named "
         "ui_hierarchy.";
}

const PIIMap& UiHierarchyDataCollector::GetDetectedPII() {
  return pii_map_;
}

void UiHierarchyDataCollector::CollectDataAndDetectPII(
    DataCollectorDoneCallback on_data_collected_callback,
    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
    scoped_refptr<redaction::RedactionToolContainer> redaction_tool_container) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  UIHierarchyData ui_hierarchy_data = CollectUiHierarchyData();
  InsertIntoPIIMap(ui_hierarchy_data.window_titles);
  data_ = std::move(ui_hierarchy_data.data);
  // `data_` can't be empty.
  DCHECK(!data_.empty());
  std::move(on_data_collected_callback).Run(/*error=*/std::nullopt);
}

void UiHierarchyDataCollector::ExportCollectedDataWithPII(
    std::set<redaction::PIIType> pii_types_to_keep,
    base::FilePath target_directory,
    scoped_refptr<base::SequencedTaskRunner> task_runner_for_redaction_tool,
    scoped_refptr<redaction::RedactionToolContainer> redaction_tool_container,
    DataCollectorDoneCallback on_exported_callback) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::MayBlock()},
      base::BindOnce(&UiHierarchyDataCollector::WriteOutputFile, data_,
                     target_directory, pii_types_to_keep),
      base::BindOnce(&UiHierarchyDataCollector::OnDataExportDone,
                     weak_ptr_factory_.GetWeakPtr(),
                     std::move(on_exported_callback)));
}

void UiHierarchyDataCollector::OnDataExportDone(
    DataCollectorDoneCallback on_exported_callback,
    bool success) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  if (!success) {
    SupportToolError error = {
        SupportToolErrorCode::kDataCollectorError,
        "UiHierarchyDataCollector failed on data export."};
    std::move(on_exported_callback).Run(error);
    return;
  }
  std::move(on_exported_callback).Run(/*error=*/std::nullopt);
}

void UiHierarchyDataCollector::InsertIntoPIIMap(
    const std::vector<std::string>& window_titles) {
  std::set<std::string>& pii_window_titles =
      pii_map_[redaction::PIIType::kUIHierarchyWindowTitles];
  for (auto const& title : window_titles)
    pii_window_titles.insert(title);
}