summaryrefslogtreecommitdiffstats
path: root/devtools/client/shared/remote-debugging/adb/adb-runtime.js
blob: 77d39d643ef79aa7d78bdae8cc3e687ffe75d6cf (plain)
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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {
  prepareTCPConnection,
} = require("resource://devtools/client/shared/remote-debugging/adb/commands/index.js");
const {
  shell,
} = require("resource://devtools/client/shared/remote-debugging/adb/commands/index.js");

class AdbRuntime {
  constructor(adbDevice, socketPath) {
    this._adbDevice = adbDevice;
    this._socketPath = socketPath;
    // Set a default version name in case versionName cannot be parsed.
    this._versionName = "";
  }

  async init() {
    const packageName = this._packageName();
    const query = `dumpsys package ${packageName} | grep versionName`;
    const versionNameString = await shell(this._adbDevice.id, query);

    // The versionName can have different formats depending on the channel
    // - `versionName=Nightly 191016 06:01\n` on Nightly
    // - `versionName=2.1.0\n` on Release
    // We use a very flexible regular expression to accommodate for those
    // different formats.
    const matches = versionNameString.match(/versionName=(.*)\n/);
    if (matches?.[1]) {
      this._versionName = matches[1];
    }
  }

  get id() {
    return this._adbDevice.id + "|" + this._socketPath;
  }

  get isFenix() {
    // Firefox Release uses "org.mozilla.firefox"
    // Firefox Beta uses "org.mozilla.firefox_beta"
    // Firefox Nightly uses "org.mozilla.fenix"
    const isFirefox =
      this._packageName().includes("org.mozilla.firefox") ||
      this._packageName().includes("org.mozilla.fenix");

    if (!isFirefox) {
      return false;
    }

    // Firefox Release (based on Fenix) is not released in all regions yet, so
    // we should still check for Fennec using the version number.
    // Note that Fennec's versionName followed Firefox versions (eg "68.11.0").
    // We can find the main version number in it. Fenix on the other hand has
    // version names such as "Nightly 200730 06:21".
    const mainVersion = Number(this.versionName.split(".")[0]);
    const isFennec = mainVersion === 68;

    // Application is Fenix if this is a Firefox application with a version
    // different from the Fennec version.
    return !isFennec;
  }

  get deviceId() {
    return this._adbDevice.id;
  }

  get deviceName() {
    return this._adbDevice.name;
  }

  get versionName() {
    return this._versionName;
  }

  get shortName() {
    const packageName = this._packageName();

    switch (packageName) {
      case "org.mozilla.firefox":
        if (!this.isFenix) {
          // Old Fennec release
          return "Firefox (Fennec)";
        }
        // Official Firefox app, based on Fenix
        return "Firefox";
      case "org.mozilla.firefox_beta":
        // Official Firefox Beta app, based on Fenix
        return "Firefox Beta";
      case "org.mozilla.fenix":
      case "org.mozilla.fenix.nightly":
        // Official Firefox Nightly app, based on Fenix
        return "Firefox Nightly";
      default:
        // Unknown package name
        return `Firefox (${packageName})`;
    }
  }

  get socketPath() {
    return this._socketPath;
  }

  get name() {
    return `${this.shortName} on Android (${this.deviceName})`;
  }

  connect(connection) {
    return prepareTCPConnection(this.deviceId, this._socketPath).then(port => {
      connection.host = "localhost";
      connection.port = port;
      connection.connect();
    });
  }

  _packageName() {
    // If using abstract socket address, it is "@org.mozilla.firefox/..."
    // If using path base socket, it is "/data/data/<package>...""
    // Until Fennec 62 only supports path based UNIX domain socket, but
    // Fennec 63+ supports both path based and abstract socket.
    return this._socketPath.startsWith("@")
      ? this._socketPath.substr(1).split("/")[0]
      : this._socketPath.split("/")[3];
  }
}
exports.AdbRuntime = AdbRuntime;