File: arc_adbd_monitor_bridge.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 (262 lines) | stat: -rw-r--r-- 9,073 bytes parent folder | download | duplicates (6)
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// Copyright 2020 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/ash/arc/adbd/arc_adbd_monitor_bridge.h"

#include <stdint.h>

#include <optional>
#include <string>
#include <utility>

#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/strings/stringprintf.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/ash/guest_os/guest_os_session_tracker.h"
#include "chrome/browser/ash/guest_os/guest_os_session_tracker_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/ash/components/system/statistics_provider.h"
#include "chromeos/ash/experiences/arc/arc_browser_context_keyed_service_factory_base.h"
#include "chromeos/ash/experiences/arc/arc_util.h"
#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"

// Enable VLOG level 1.
#undef ENABLED_VLOG_LEVEL
#define ENABLED_VLOG_LEVEL 1

namespace arc {

namespace {

// The "_2d" in job names below corresponds to "-". Upstart escapes characters
// that aren't valid in D-Bus object paths with underscore followed by its
// ascii code in hex. So "arc_2dcreate_2ddata" becomes "arc-create-data".
constexpr const char kArcVmAdbdJobName[] = "arcvm_2dadbd";
// developer mode
constexpr const char kCrosDebug[] = "cros_debug";
// udc enabled
constexpr const char kCrosUdcEnabled[] = "dev_enable_udc";
// adbd.json
constexpr const char kAdbdJson[] = "/etc/arc/adbd.json";

bool g_enable_adb_over_usb_for_testing = false;

// Singleton factory for ArcAdbdMonitorBridge.
class ArcAdbdMonitorBridgeFactory
    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
          ArcAdbdMonitorBridge,
          ArcAdbdMonitorBridgeFactory> {
 public:
  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
  static constexpr const char* kName = "ArcAdbdMonitorBridgeFactory";

  static ArcAdbdMonitorBridgeFactory* GetInstance() {
    return base::Singleton<ArcAdbdMonitorBridgeFactory>::get();
  }

 private:
  friend base::DefaultSingletonTraits<ArcAdbdMonitorBridgeFactory>;
  ArcAdbdMonitorBridgeFactory() = default;
  ~ArcAdbdMonitorBridgeFactory() override = default;
};

// Returns true if the daemon for adb-over-usb should be started on the device.
bool ShouldStartAdbd(bool is_dev_mode,
                     bool is_host_on_vm,
                     bool has_adbd_json,
                     bool is_adb_over_usb_disabled) {
  // Do the same check as ArcSetup::MaybeStartAdbdProxy().
  return is_dev_mode && !is_host_on_vm && has_adbd_json &&
         !is_adb_over_usb_disabled;
}

// Returns true if adb-over-usb feature is enabled on Chrome OS.
bool IsAdbOverUsbEnabled() {
  // True when in developer mode.
  bool is_dev_mode = GetSystemPropertyInt(kCrosDebug) == 1;
  // True when udc is disabled.
  bool udc_disabled = GetSystemPropertyInt(kCrosUdcEnabled) == 0;
  // True when adbd json is established. Required for adb-over-usb feature.
  bool has_adbd_json = base::PathExists(base::FilePath(kAdbdJson));
  // True when the *host* is running on a VM.
  bool is_host_on_vm =
      ash::system::StatisticsProvider::GetInstance()->IsRunningOnVm();
  bool is_adb_over_usb_enabled =
      ShouldStartAdbd(is_dev_mode, is_host_on_vm, has_adbd_json, udc_disabled);
  return g_enable_adb_over_usb_for_testing || is_adb_over_usb_enabled;
}

// Returns cid from vm info. Otherwise, return nullopt.
std::optional<int64_t> GetCid() {
  Profile* const profile = arc::ArcSessionManager::Get()->profile();
  if (!profile) {
    LOG(ERROR) << "Profile is not ready";
    return std::nullopt;
  }
  const auto& vm_info =
      guest_os::GuestOsSessionTrackerFactory::GetForProfile(profile)->GetVmInfo(
          kArcVmName);
  if (!vm_info) {
    LOG(ERROR) << "ARCVM is NOT ready";
    return std::nullopt;
  }
  return vm_info->cid();
}

std::string GetSerialNumber() {
  return arc::ArcSessionManager::Get()->GetSerialNumber();
}

std::optional<std::vector<std::string>> CreateAndGetAdbdUpstartEnvironment() {
  auto cid = GetCid();
  if (!cid) {
    LOG(ERROR) << "ARCVM cid is empty";
    return std::nullopt;
  }
  auto serial_number = GetSerialNumber();
  if (serial_number.empty()) {
    LOG(ERROR) << "Serial number is empty";
    return std::nullopt;
  }

  std::vector<std::string> environment = {
      "SERIALNUMBER=" + serial_number,
      base::StringPrintf("ARCVM_CID=%" PRId64, cid.value())};
  return environment;
}

}  // namespace

// static
ArcAdbdMonitorBridge* ArcAdbdMonitorBridge::GetForBrowserContext(
    content::BrowserContext* context) {
  return ArcAdbdMonitorBridgeFactory::GetForBrowserContext(context);
}

// static
ArcAdbdMonitorBridge* ArcAdbdMonitorBridge::GetForBrowserContextForTesting(
    content::BrowserContext* context) {
  return ArcAdbdMonitorBridgeFactory::GetForBrowserContextForTesting(context);
}

ArcAdbdMonitorBridge::ArcAdbdMonitorBridge(content::BrowserContext* context,
                                           ArcBridgeService* bridge_service)
    : arc_bridge_service_(bridge_service) {
  VLOG(1) << "Init ArcAdbdMonitorBridge";
  arc_bridge_service_->adbd_monitor()->SetHost(this);
  arc_bridge_service_->adbd_monitor()->AddObserver(this);
}

ArcAdbdMonitorBridge::~ArcAdbdMonitorBridge() {
  arc_bridge_service_->adbd_monitor()->RemoveObserver(this);
  arc_bridge_service_->adbd_monitor()->SetHost(nullptr);
}

void ArcAdbdMonitorBridge::AdbdStarted() {
  VLOG(1) << "Received adbd start signal arcvm-adbd";
  StartArcVmAdbd(base::DoNothing());
}

void ArcAdbdMonitorBridge::AdbdStopped() {
  StopArcVmAdbd(base::DoNothing());
}

void ArcAdbdMonitorBridge::OnConnectionReady() {
  VLOG(1) << "Mojo connection is ready";
}

void ArcAdbdMonitorBridge::EnableAdbOverUsbForTesting() {
  g_enable_adb_over_usb_for_testing = true;
}

void ArcAdbdMonitorBridge::OnAdbdStartedForTesting(
    chromeos::VoidDBusMethodCallback callback) {
  StartArcVmAdbd(std::move(callback));
}

void ArcAdbdMonitorBridge::OnAdbdStoppedForTesting(
    chromeos::VoidDBusMethodCallback callback) {
  StopArcVmAdbd(std::move(callback));
}

void ArcAdbdMonitorBridge::StartArcVmAdbd(
    chromeos::VoidDBusMethodCallback callback) {
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
      base::BindOnce(&IsAdbOverUsbEnabled),
      base::BindOnce(&ArcAdbdMonitorBridge::StartArcVmAdbdInternal,
                     weak_factory_.GetWeakPtr(), std::move(callback)));
}

void ArcAdbdMonitorBridge::StartArcVmAdbdInternal(
    chromeos::VoidDBusMethodCallback callback,
    bool adb_over_usb_enabled) {
  if (!adb_over_usb_enabled) {
    // No need to start arcvm-adbd job. Run the |callback| now.
    std::move(callback).Run(/*result=*/true);
    return;
  }
  // Start the daemon for supporting adb-over-usb.
  VLOG(1) << "Starting arcvm-adbd";
  auto environment = CreateAndGetAdbdUpstartEnvironment();
  if (!environment) {
    LOG(ERROR)
        << "Cannot start arcvm-adbd job since upstart environment is unknown";
    std::move(callback).Run(/*result=*/false);
    return;
  }

  std::deque<JobDesc> jobs{JobDesc{kArcVmAdbdJobName,
                                   UpstartOperation::JOB_STOP_AND_START,
                                   std::move(environment.value())}};
  ConfigureUpstartJobs(std::move(jobs), std::move(callback));
}

void ArcAdbdMonitorBridge::StopArcVmAdbd(
    chromeos::VoidDBusMethodCallback callback) {
  base::ThreadPool::PostTaskAndReplyWithResult(
      FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE},
      base::BindOnce(&IsAdbOverUsbEnabled),
      base::BindOnce(&ArcAdbdMonitorBridge::StopArcVmAdbdInternal,
                     weak_factory_.GetWeakPtr(), std::move(callback)));
}

void ArcAdbdMonitorBridge::StopArcVmAdbdInternal(
    chromeos::VoidDBusMethodCallback callback,
    bool adb_over_usb_enabled) {
  if (!adb_over_usb_enabled) {
    // No need to stop arcvm-adbd job. Run the |callback| now.
    std::move(callback).Run(/*result=*/true);
    return;
  }
  // Stop the daemon for supporting adb-over-usb.
  VLOG(1) << "Stopping arcvm-adbd";
  auto environment = CreateAndGetAdbdUpstartEnvironment();
  if (!environment) {
    // Adbd upstart environment is not ready, please see error log.
    LOG(ERROR) << "Cannot stop arcvm-adbd job since upstart environment "
                  "is unknown";
    std::move(callback).Run(/*result=*/false);
    return;
  }

  std::deque<JobDesc> jobs{JobDesc{kArcVmAdbdJobName,
                                   UpstartOperation::JOB_STOP,
                                   std::move(environment.value())}};
  ConfigureUpstartJobs(std::move(jobs), std::move(callback));
}

// static
void ArcAdbdMonitorBridge::EnsureFactoryBuilt() {
  ArcAdbdMonitorBridgeFactory::GetInstance();
}

}  // namespace arc