File: language_pack_manager.h

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; 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,806; 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 (312 lines) | stat: -rw-r--r-- 11,792 bytes parent folder | download | duplicates (7)
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
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
// 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.

#ifndef CHROMEOS_ASH_COMPONENTS_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_
#define CHROMEOS_ASH_COMPONENTS_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_

#include <optional>
#include <string>
#include <string_view>

#include "base/containers/flat_map.h"
#include "base/functional/callback.h"
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/sequence_checker.h"
#include "base/strings/strcat.h"
#include "chromeos/ash/components/dbus/dlcservice/dlcservice_client.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "ui/base/ime/ash/input_method_util.h"

class PrefService;

namespace ash::language_packs {

// All Language Pack IDs are listed here.
inline constexpr char kHandwritingFeatureId[] = "LP_ID_HANDWRITING";
inline constexpr char kTtsFeatureId[] = "LP_ID_TTS";
inline constexpr char kFontsFeatureId[] = "LP_ID_FONT";

// Feature IDs.
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// See enum LanguagePackFeatureIds in tools/metrics/histograms/enums.xml.
enum class FeatureIdsEnum {
  kUnknown = 0,
  kHandwriting = 1,
  kTts = 2,
  kFonts = 3,
  kMaxValue = kFonts,
};

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// See enum LanguagePackFeatureSuccess in tools/metrics/histograms/enums.xml.
enum class FeatureSuccessEnum {
  kUnknownSuccess = 0,
  kUnknownFailure = 1,
  kHandwritingSuccess = 2,
  kHandwritingFailure = 3,
  kTtsSuccess = 4,
  kTtsFailure = 5,
  kFontsSuccess = 6,
  kFontsFailure = 7,
  kMaxValue = kFontsFailure,
};

// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
// See enum LanguagePackDlcErrorType in tools/metrics/histograms/enums.xml.
enum class DlcErrorTypeEnum {
  kErrorUnknown = 0,
  kErrorNone = 1,
  kErrorInternal = 2,
  kErrorBusy = 3,
  kErrorNeedReboot = 4,
  kErrorInvalidDlc = 5,
  kErrorAllocation = 6,
  kErrorNoImageFound = 7,
  kMaxValue = kErrorNoImageFound,
};

// Status contains information about the status of a Language Pack operation.
struct PackResult {
  // Needed for Complex type checker.
  PackResult();
  ~PackResult();
  PackResult(const PackResult&);

  enum class StatusCode {
    kUnknown = 0,
    kNotInstalled,
    kInProgress,
    kInstalled
  };

  enum class ErrorCode {
    kNone = 0,
    kOther,
    kWrongId,
    kNeedReboot,
    kAllocation
  };

  // The code that indicates the current state of the Pack.
  // kInstalled means that the Pack is ready to be used.
  // If there's any error during the operation, we set status to kUnknown.
  StatusCode pack_state;

  // If there is any error in the operation that is requested, it is indicated
  // here.
  ErrorCode operation_error;

  // The feature ID of the pack.
  std::string feature_id;

  // The resolved language code that this Pack is associated with.
  // Often this field matches the locale requested by the client, but due to
  // various mappings between languages, regions and variants, it might be
  // different.
  // This is set only if the input locale is valid; undetermined otherwise.
  std::string language_code;

  // The path where the Pack is available for users to use.
  std::string path;
};

// We define an internal type to identify a Language Pack.
// It's a pair of featured_id and locale that is hashable.
struct PackSpecPair {
  std::string feature_id;
  std::string locale;

  PackSpecPair(std::string feature_id, std::string locale)
      : feature_id(std::move(feature_id)), locale(std::move(locale)) {}

  bool operator==(const PackSpecPair& other) const {
    return (feature_id == other.feature_id && locale == other.locale);
  }

  bool operator!=(const PackSpecPair& other) const { return !(*this == other); }

  // Allows PackSpecPair to be used as a key in STL containers, like flat_map.
  bool operator<(const PackSpecPair& other) const {
    if (feature_id == other.feature_id) {
      return locale < other.locale;
    }

    return feature_id < other.feature_id;
  }

  // Simple hash function: XOR the string hash.
  struct HashFunction {
    size_t operator()(const PackSpecPair& obj) const {
      size_t first_hash = std::hash<std::string>()(obj.feature_id);
      size_t second_hash = std::hash<std::string>()(obj.locale) << 1;
      return first_hash ^ second_hash;
    }
  };
};

// Returns a static mapping from `PackSpecPair`s to DLC IDs.
// Internal only, do not use - this function will likely be removed in the
// future.
const base::flat_map<PackSpecPair, std::string>& GetAllLanguagePackDlcIds();

// Finds the ID of the DLC corresponding to the given spec.
// Returns the DLC ID if the DLC exists or std::nullopt otherwise.
std::optional<std::string> GetDlcIdForLanguagePack(
    const std::string& feature_id,
    const std::string& locale);

using OnInstallCompleteCallback =
    base::OnceCallback<void(const PackResult& pack_result)>;
using GetPackStateCallback =
    base::OnceCallback<void(const PackResult& pack_result)>;
using OnUninstallCompleteCallback =
    base::OnceCallback<void(const PackResult& pack_result)>;
using OnInstallBasePackCompleteCallback =
    base::OnceCallback<void(const PackResult& pack_result)>;
using OnUpdatePacksForOobeCallback =
    base::OnceCallback<void(const PackResult& pack_result)>;

// This class manages all Language Packs and their dependencies (called Base
// Packs) on the device.
// This is a Singleton and needs to be accessed via Get().
//
// Sequencing: This class is sequence-checked so all accesses to it - non-static
// methods, `Initialise()` and `Shutdown()` - should be done on the same
// sequence. This may be overly strict, see b/319906094 for more details.
class LanguagePackManager : public DlcserviceClient::Observer {
 public:
  // Observer of Language Packs.
  // TODO(crbug.com/1194688): Make the Observers dependent on feature and
  // locale, so that clients don't get notified for things they are not
  // interested in.
  class Observer : public base::CheckedObserver {
   public:
    // Called whenever the state of a Language Pack changes, which includes
    // installation, download, removal or errors.
    virtual void OnPackStateChanged(const PackResult& pack_result) = 0;
  };

  // Do not use unless in tests.
  // Only one `LanguagePackManager` can be instantiated at any time.
  // Use `GetInstance()` instead to obtain the currently instantiated instance,
  // likely instantiated by `Initialise()`.
  LanguagePackManager();

  // Disallow copy and assign.
  LanguagePackManager(const LanguagePackManager&) = delete;
  LanguagePackManager& operator=(const LanguagePackManager&) = delete;

  ~LanguagePackManager() override;

  // Returns true if the given Language Pack exists and can be installed on
  // this device.
  // TODO(claudiomagni): Check per board.
  static bool IsPackAvailable(const std::string& feature_id,
                              const std::string& locale);

  // Installs the Language Pack.
  // It takes a callback that will be triggered once the operation is done.
  // A state is passed to the callback.
  static void InstallPack(const std::string& feature_id,
                          const std::string& locale,
                          OnInstallCompleteCallback callback);

  // Checks the state of a Language Pack.
  // It takes a callback that will be triggered once the operation is done.
  // A state is passed to the callback.
  // If the state marks the Language Pack as ready, then there's no need to
  // call Install(), otherwise the client should call Install() and not call
  // this method a second time.
  // This will automatically mount the DLC if it exists on disk (is_verified),
  // and return a PackState of kInstalled.
  static void GetPackState(const std::string& feature_id,
                           const std::string& locale,
                           GetPackStateCallback callback);

  // Features should call this method to indicate that they do not intend to
  // use the Pack again, until they will call |InstallPack()|.
  // The Language Pack will be removed from disk, but no guarantee is given on
  // when that will happen.
  // TODO(claudiomagni): Allow callers to force immediate removal. Useful to
  //                     clear space on disk for another language.
  static void RemovePack(const std::string& feature_id,
                         const std::string& locale,
                         OnUninstallCompleteCallback callback);

  // Explicitly installs the base pack for |feature_id|.
  static void InstallBasePack(const std::string& feature_id,
                              OnInstallBasePackCompleteCallback callback);

  // Installs relevant language packs during OOBE.
  // This method should only be called during OOBE and will do nothing if called
  // outside it.
  static void UpdatePacksForOobe(const std::string& locale,
                                 OnUpdatePacksForOobeCallback callback);

  // Registers itself as an Observer of all the relevant languages Prefs.
  void ObservePrefs(PrefService* pref_service);

  // Adds an observer to the observer list.
  void AddObserver(Observer* observer);

  // Removes an observer from the observer list.
  void RemoveObserver(Observer* observer);

  // Initialises the global instance. This is typically called from
  // ash_dbus_helper.h's `InitializeDBus()`, which is called from
  // `ChromeMainDelegate::PostEarlyInitialization()`.
  // Cannot be called multiple times - `GetInstance()` must return `nullptr`
  // before this static method is called.
  // Requires the global `DlcserviceClient` to be initialised.
  // Do not use this in tests, instantiate a test-local `LanguagePackManager`
  // instead.
  static void Initialise();

  // Shuts down the global instance. This is typically called from
  // ash_dbus_helper.h's `ShutdownDBus()`, which is called from
  // `ChromeBrowserMainPartsAsh::PostDestroyThreads()`.
  // Cannot be called multiple times - `GetInstance()` must return a non-null
  // pointer before this static method is called.
  // The global `DlcserviceClient` at the time of initialisation must still
  // exist when this is called.
  // Do not use this in tests, the destructor of the test-local
  // `LanguagePackManager` will correctly unset the currently instantiated
  // instance.
  static void Shutdown();

  // Returns the currently instantiated instance. This is typically the global
  // instance, but may be a test-local `LanguagePackManager` during tests.
  static LanguagePackManager* GetInstance();

 private:
  // Retrieves the list of installed DLCs and updates Packs accordingly.
  // This function should be called when LPM initializes and then each time
  // Prefs change.
  static void CheckAndUpdateDlcsForInputMethods(PrefService* pref_service);

  // DlcserviceClient::Observer overrides.
  void OnDlcStateChanged(const dlcservice::DlcState& dlc_state) override;

  // Notification method called upon change of DLCs state.
  void NotifyPackStateChanged(std::string_view feature_id,
                              std::string_view locale,
                              const dlcservice::DlcState& dlc_state)
      VALID_CONTEXT_REQUIRED(sequence_checker_);

  SEQUENCE_CHECKER(sequence_checker_);

  base::ObserverList<Observer> observers_;
  base::ScopedObservation<DlcserviceClient, DlcserviceClient::Observer> obs_{
      this};
  PrefChangeRegistrar pref_change_registrar_;
};

}  // namespace ash::language_packs

#endif  // CHROMEOS_ASH_COMPONENTS_LANGUAGE_PACKS_LANGUAGE_PACK_MANAGER_H_