File: app_shim_manager_mac.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (528 lines) | stat: -rw-r--r-- 23,196 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
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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_MANAGER_MAC_H_
#define CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_MANAGER_MAC_H_

#include <Security/Security.h>

#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>

#include "apps/app_lifetime_monitor.h"
#include "base/apple/scoped_cftyperef.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/apps/app_shim/app_shim_host_bootstrap_mac.h"
#include "chrome/browser/apps/app_shim/app_shim_host_mac.h"
#include "chrome/browser/badging/badge_manager.h"
#include "chrome/browser/profiles/avatar_menu_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager_observer.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/common/mac/app_shim.mojom.h"
#include "chrome/services/mac_notifications/public/mojom/mac_notifications.mojom.h"
#include "components/webapps/common/web_app_id.h"

class Profile;
class ProfileManager;

namespace base {
class FilePath;
}  // namespace base

namespace content {
class BrowserContext;
}  // namespace content

namespace apps {

// The passed in `callback` will be called when all launches for the next app
// shim launch have completed (all profiles the app will launch in, as well
// as possibly multiple windows within profiles).
void SetMacShimStartupDoneCallbackForTesting(base::OnceClosure callback);

// Returns the callback set with SetMacShimStartupDoneCallbackForTesting;
base::OnceClosure TakeShimStartupDoneCallbackForTesting();

// This app shim handler that handles events for app shims that correspond to an
// extension.
class AppShimManager
    : public AppShimHostBootstrap::Client,
      public AppShimHost::Client,
      public AppLifetimeMonitor::Observer,
      public BrowserListObserver,
      public AvatarMenuObserver,
      public ProfileManagerObserver,
      public ProfileObserver,
      public mac_notifications::mojom::MacNotificationProvider,
      public mac_notifications::mojom::MacNotificationActionHandler {
 public:
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // Show all app windows (for non-PWA apps). Return true if there existed any
    // windows.
    virtual bool ShowAppWindows(Profile* profile,
                                const webapps::AppId& app_id) = 0;

    // Close all app windows (for non-PWA apps).
    virtual void CloseAppWindows(Profile* profile,
                                 const webapps::AppId& app_id) = 0;

    // Return true iff |app_id| corresponds to an app that is installed for
    // |profile|. Note that |profile| may be nullptr (in which case it should
    // always return false).
    virtual bool AppIsInstalled(Profile* profile,
                                const webapps::AppId& app_id) = 0;

    // Return true iff the specified app can create an AppShimHost, which will
    // keep the app shim process connected (as opposed to, e.g, a bookmark app
    // that opens in a tab, which will immediately close).
    virtual bool AppCanCreateHost(Profile* profile,
                                  const webapps::AppId& app_id) = 0;

    // Return true if Cocoa windows for this app should be hosted in the app
    // shim process.
    virtual bool AppUsesRemoteCocoa(Profile* profile,
                                    const webapps::AppId& app_id) = 0;

    // Return true if a single app shim is used for all profiles (as opposed to
    // one shim per profile).
    virtual bool AppIsMultiProfile(Profile* profile,
                                   const webapps::AppId& app_id) = 0;

    // Open a dialog to enable the specified extension. Call |callback| after
    // the dialog is executed.
    virtual void EnableExtension(Profile* profile,
                                 const std::string& extension_id,
                                 base::OnceCallback<void()> callback) = 0;

    // Launch the app in Chrome. This will (often) create a new window. It is
    // guaranteed that |app_id| is installed for |profile| when this method
    // is called.
    virtual void LaunchApp(
        Profile* profile,
        const webapps::AppId& app_id,
        const std::vector<base::FilePath>& files,
        const std::vector<GURL>& urls,
        const GURL& override_url,
        chrome::mojom::AppShimLoginItemRestoreState login_item_restore_state,
        base::OnceClosure launch_finished_callback) = 0;

    // Launch the shim process for an app. It is guaranteed that |app_id| is
    // installed for |profile| when this method is called.
    virtual void LaunchShim(Profile* profile,
                            const webapps::AppId& app_id,
                            web_app::LaunchShimUpdateBehavior update_behavior,
                            web_app::ShimLaunchMode launch_mode,
                            ShimLaunchedCallback launched_callback,
                            ShimTerminatedCallback terminated_callback) = 0;

    // Return true if any app windows are open. This is eventually invoked
    // by MaybeTerminate. It does not apply to bookmark apps.
    virtual bool HasNonBookmarkAppWindowsOpen() = 0;

    virtual std::vector<chrome::mojom::ApplicationDockMenuItemPtr>
    GetAppShortcutsMenuItemInfos(Profile* profile,
                                 const webapps::AppId& app_id) = 0;
  };

  // Helper function to get the instance on the browser process. This will be
  // non-null except for tests.
  static AppShimManager* Get();

  explicit AppShimManager(std::unique_ptr<Delegate> delegate);
  AppShimManager(const AppShimManager&) = delete;
  AppShimManager& operator=(const AppShimManager&) = delete;
  ~AppShimManager() override;

  // Get the host corresponding to a profile and app id, or null if there is
  // none.
  AppShimHost* FindHost(Profile* profile, const webapps::AppId& app_id);

  // If the specified |browser| should be using RemoteCocoa (because it is a
  // bookmark app), then get or create an AppShimHost for it, and return
  // it. If an AppShimHost had to be created (e.g, because the app process is
  // still launching), create one, which will bind to the app process when it
  // finishes launching.
  AppShimHost* GetHostForRemoteCocoaBrowser(Browser* browser);

  // Returns true if the specified `browser` should be using RemoteCocoa. This
  // is equivalent to `GetHostForRemoteCocoaBrowser` return a non-null value,
  // except that this method does not cause an AppShimHost to be created.
  bool BrowserUsesRemoteCocoa(Browser* browser);

  // Return true if any non-bookmark app windows open.
  bool HasNonBookmarkAppWindowsOpen();

  // Called when the launch of the app was cancelled by the user. For example,
  // if the user clicks cancel during a protocol launch.
  void OnAppLaunchCancelled(content::BrowserContext* context,
                            const std::string& app_id);

  void UpdateAppBadge(
      Profile* profile,
      const webapps::AppId& app_id,
      const std::optional<badging::BadgeManager::BadgeValue>& badge);

  // Called to connect to a MacNotificationProvider instance in the app shim
  // process for the given app_id. This is only supported for multi-profile
  // app shims; but only legacy platform apps would use single-profile shims
  // anyway.
  // If there is no running app shim matching `app_id`, currently this method
  // instead returns a remote connected to a dummy notification provider. In
  // the future this will instead launch an app shim for `app_id` and connect
  // to that.
  mojo::Remote<mac_notifications::mojom::MacNotificationProvider>
  LaunchNotificationProvider(const webapps::AppId& app_id);

  // Triggers an OS-level notification permission request prompt to be shown by
  // the app shim corresponding to `app_id`. Returns the current state without
  // showing a prompt if permission has already been granted and/or denied to
  // the app shim.
  using RequestNotificationPermissionCallback =
      chrome::mojom::AppShim::RequestNotificationPermissionCallback;
  void ShowNotificationPermissionRequest(
      const webapps::AppId& app_id,
      RequestNotificationPermissionCallback callback);

  // Causes ShowNotificationPermissionRequest() to immediately call its callback
  // with the given `result`, rather than trying to request permission from the
  // app shim.
  void SetNotificationPermissionResponseForTesting(
      mac_notifications::mojom::RequestPermissionResult result) {
    notification_permission_result_for_testing_ = result;
  }

  // Opens the given app in the given profile in response to the user picking
  // said profile in the Profiles menu.
  void LaunchAppInProfile(const webapps::AppId& app_id,
                          const base::FilePath& profile_path);

  // AppShimHostBootstrap::Client:
  void OnShimProcessConnected(
      std::unique_ptr<AppShimHostBootstrap> bootstrap) override;

  // AppShimHost::Client:
  void OnShimLaunchRequested(
      AppShimHost* host,
      web_app::LaunchShimUpdateBehavior update_behavior,
      web_app::ShimLaunchMode launch_mode,
      base::OnceCallback<void(base::Process)> launched_callback,
      base::OnceClosure terminated_callback) override;
  void OnShimProcessDisconnected(AppShimHost* host) override;
  void OnShimFocus(AppShimHost* host) override;
  void OnShimReopen(AppShimHost* host) override;
  void OnShimOpenedFiles(AppShimHost* host,
                         const std::vector<base::FilePath>& files) override;
  void OnShimSelectedProfile(AppShimHost* host,
                             const base::FilePath& profile_path) override;
  void OnShimOpenedAppSettings(AppShimHost* host) override;
  void OnShimOpenedUrls(AppShimHost* host,
                        const std::vector<GURL>& urls) override;
  void OnShimOpenAppWithOverrideUrl(AppShimHost* host,
                                    const GURL& override_url) override;
  void OnShimWillTerminate(AppShimHost* host) override;
  void OnNotificationPermissionStatusChanged(
      AppShimHost* host,
      mac_notifications::mojom::PermissionStatus status) override;

  // AppLifetimeMonitor::Observer overrides:
  void OnAppStart(content::BrowserContext* context,
                  const std::string& app_id) override;
  void OnAppActivated(content::BrowserContext* context,
                      const std::string& app_id) override;
  void OnAppDeactivated(content::BrowserContext* context,
                        const std::string& app_id) override;
  void OnAppStop(content::BrowserContext* context,
                 const std::string& app_id) override;

  // ProfileManagerObserver overrides:
  void OnProfileAdded(Profile* profile) override;
  void OnProfileMarkedForPermanentDeletion(Profile* profile) override;
  void OnProfileManagerDestroying() override;

  // BrowserListObserver overrides:
  void OnBrowserAdded(Browser* browser) override;
  void OnBrowserRemoved(Browser* browser) override;
  void OnBrowserSetLastActive(Browser* browser) override;

  // ProfileObserver overrides:
  void OnProfileWillBeDestroyed(Profile* profile) override;

  // AvatarMenuObserver:
  void OnAvatarMenuChanged(AvatarMenu* menu) override;

  static base::apple::ScopedCFTypeRef<CFStringRef>
      BuildAppShimRequirementStringFromFrameworkRequirementString(CFStringRef);

  class AppShimObserver {
   public:
    virtual void OnShimProcessConnected(base::ProcessId pid) {}
    virtual void OnShimProcessConnectedAndAllLaunchesDone(
        base::ProcessId pid,
        chrome::mojom::AppShimLaunchResult result) {}
    virtual void OnShimReopen(base::ProcessId pid) {}
    virtual void OnShimOpenedURLs(base::ProcessId pid) {}
    // If this is overridden to return false, the regular notification action
    // code path is bypassed.
    virtual bool OnNotificationAction(
        mac_notifications::mojom::NotificationActionInfoPtr& info);
  };
  void SetAppShimObserverForTesting(AppShimObserver* observer) {
    app_shim_observer_ = observer;
  }

  // Simulates a launch as triggered by an app shim for the specific `app_id`.
  void LoadAndLaunchAppForTesting(const webapps::AppId& app_id);

 protected:
  typedef std::set<Browser*> BrowserSet;

  // Virtual for tests.
  virtual bool IsAcceptablyCodeSigned(audit_token_t audit_token) const;

  // Return the profile for |path|, only if it is already loaded.
  virtual Profile* ProfileForPath(const base::FilePath& path);

  // Return a profile to use for a background shim launch, virtual for tests.
  virtual Profile* ProfileForBackgroundShimLaunch(const webapps::AppId& app_id);

  // Load a profile and call |callback| when completed or failed.
  virtual void LoadProfileAsync(const base::FilePath& path,
                                base::OnceCallback<void(Profile*)> callback);

  // Wait for |profile|'s WebAppProvider registry to be started.
  virtual void WaitForAppRegistryReadyAsync(
      Profile* profile,
      base::OnceCallback<void()> callback);

  // Return true if the specified path is for a valid profile that is also
  // locked.
  virtual bool IsProfileLockedForPath(const base::FilePath& path);

  // Create an AppShimHost for the specified parameters (intercept-able for
  // tests).
  virtual std::unique_ptr<AppShimHost> CreateHost(
      AppShimHost::Client* client,
      const base::FilePath& profile_path,
      const webapps::AppId& app_id,
      bool use_remote_cocoa);

  // Open the specified URL in a new Chrome window. This is the fallback when
  // an app shim exists, but there is no profile or extension for it. If
  // |profile_path| is specified, then that profile is preferred, otherwise,
  // the last used profile is used.
  virtual void OpenAppURLInBrowserWindow(const base::FilePath& profile_path,
                                         const GURL& url);

  // Launch the user manager (in response to attempting to access a locked
  // profile).
  virtual void LaunchProfilePicker();

  // Terminate Chrome if Chrome attempted to quit, but was prevented from
  // quitting due to apps being open.
  virtual void MaybeTerminate();

  // Called when profile menu items may have changed. Rebuilds the profile
  // menu item list and sends updated lists to all apps.
  void UpdateAllProfileMenus();

  // Update |profile_menu_items_| from |avatar_menu_|. Virtual for tests.
  virtual void RebuildProfileMenuItemsFromAvatarMenu();

  // The list of all profiles that might appear in the menu.
  std::vector<chrome::mojom::ProfileMenuItemPtr> profile_menu_items_;

 private:
  friend class ScopedAppShimKeepAlive;

  // The state for an individual app, and for the profile-scoped app info.
  struct ProfileState;
  struct AppState;

  // Close all app shims associated with the specified profile.
  void CloseShimsForProfile(Profile* profile);

  // This is called by OnShimProcessConnected if the app shim was launched by
  // Chrome, and should connect to an already-existing AppShimHost.
  void OnShimProcessConnectedForRegisterOnly(
      std::unique_ptr<AppShimHostBootstrap> bootstrap);

  // The function LoadAndLaunchApp will:
  // - Find the appropriate profiles for which |app_id| should be launched.
  // - Load the profiles and ensure the app is enabled (using
  //   LoadProfileAndApp), if needed.
  // - Launch the app, if appropriate.
  // The "if appropriate" above is defined as:
  // - If `params.files` is non-empty, then will always launch the app
  //   - If `profile_path` is non-empty, then use that profile.
  //   - In the most recently used profile, otherwise
  // - If `params.files` is empty, then launch the app only if:
  //   - If `profile_path` is non-empty, then launch if the app is not running
  //     in that profile.
  //   - Otherwise, launch the app only if it is not running any profile.
  using LoadAndLaunchAppCallback =
      base::OnceCallback<void(ProfileState* profile_state,
                              chrome::mojom::AppShimLaunchResult result)>;
  struct LoadAndLaunchAppParams {
    LoadAndLaunchAppParams();
    ~LoadAndLaunchAppParams();
    LoadAndLaunchAppParams(const LoadAndLaunchAppParams&);
    LoadAndLaunchAppParams& operator=(const LoadAndLaunchAppParams&);

    // Return true if `files` or `urls` is non-empty. If so, then this launch
    // will open exactly one window.
    bool HasFilesOrURLs() const;

    webapps::AppId app_id;
    std::vector<base::FilePath> files;
    std::vector<GURL> urls;
    GURL override_url;
    chrome::mojom::AppShimLoginItemRestoreState login_item_restore_state =
        chrome::mojom::AppShimLoginItemRestoreState::kNone;
  };
  void LoadAndLaunchApp(const base::FilePath& profile_path,
                        const LoadAndLaunchAppParams& params,
                        LoadAndLaunchAppCallback launch_callback);
  bool LoadAndLaunchApp_TryExistingProfileStates(
      const base::FilePath& profile_path,
      const LoadAndLaunchAppParams& params,
      const std::map<base::FilePath, int>& profiles_with_handlers,
      LoadAndLaunchAppCallback* launch_callback);
  void LoadAndLaunchApp_OnProfilesAndAppReady(
      const std::vector<base::FilePath>& profile_paths_to_launch,
      bool first_profile_is_from_bootstrap,
      const LoadAndLaunchAppParams& params,
      LoadAndLaunchAppCallback launch_callback);
  void LoadAndLaunchApp_LaunchIfAppropriate(
      Profile* profile,
      ProfileState* profile_state,
      const LoadAndLaunchAppParams& params,
      base::OnceClosure launch_finished_callback);

  // The final step of both paths for OnShimProcessConnected. This will connect
  // |bootstrap| to |profile_state|'s AppShimHost, if possible. The value of
  // |profile_state| is non-null if and only if |result| is success.
  void OnShimProcessConnectedAndAllLaunchesDone(
      std::unique_ptr<AppShimHostBootstrap> bootstrap,
      ProfileState* profile_state,
      chrome::mojom::AppShimLaunchResult result);

  // Load the specified profile and extension, and run |callback| with
  // the result. The callback's arguments may be nullptr on failure.
  using LoadProfileAndAppCallback = base::OnceCallback<void(Profile*)>;
  void LoadProfileAndApp(const base::FilePath& profile_path,
                         const webapps::AppId& app_id,
                         LoadProfileAndAppCallback callback);
  void LoadProfileAndApp_OnProfileLoaded(const base::FilePath& profile_path,
                                         const webapps::AppId& app_id,
                                         LoadProfileAndAppCallback callback,
                                         Profile* profile);
  void LoadProfileAndApp_OnProfileAppRegistryReady(
      const base::FilePath& profile_path,
      const webapps::AppId& app_id,
      LoadProfileAndAppCallback callback);
  void LoadProfileAndApp_OnAppEnabled(const base::FilePath& profile_path,
                                      const webapps::AppId& app_id,
                                      LoadProfileAndAppCallback callback);

  // Update the profiles menu for the specified host.
  void UpdateAppProfileMenu(AppState* app_state);

  // Update the application dock menu for the specified host.
  void UpdateApplicationDockMenu(Profile* profile, ProfileState* profile_state);

  // Updates the badge for the specified host.
  void UpdateApplicationBadge(ProfileState* profile_state);

  // Retrieve the ProfileState for a given (Profile, AppId) pair. If one
  // does not exist, create one.
  ProfileState* GetOrCreateProfileState(Profile* profile,
                                        const webapps::AppId& app_id);

  // Launches a shim for `app_id` in background mode (i.e. without being shown
  // in the Dock and other UI surfaces). Can call `callback` with nullptr if the
  // `app_id` is invalid (for example not installed locally in any profile). If
  // the launch itself fails, this will still call `callback` with a valid
  // AppShimHost, but a mojo connection to the app shim will never be
  // established (and any calls that were made to the remote app shim will be
  // dropped).
  void LaunchShimInBackgroundMode(
      const webapps::AppId& app_id,
      base::OnceCallback<void(AppShimHost*)> callback);

  // Returns a mapping of profile paths to how many of the files and urls passed
  // in in `params` each profile can handle.
  static std::map<base::FilePath, int> GetProfilesWithMatchingHandlers(
      const LoadAndLaunchAppParams& params);

  // mac_notifications::mojom::MacNotificationProvider:
  void BindNotificationService(
      mojo::PendingReceiver<mac_notifications::mojom::MacNotificationService>
          service,
      mojo::PendingRemote<
          mac_notifications::mojom::MacNotificationActionHandler> handler)
      override;

  // mac_notifications::mojom::MacNotificationActionHandler:
  void OnNotificationAction(
      mac_notifications::mojom::NotificationActionInfoPtr info) override;

  std::unique_ptr<Delegate> delegate_;

  // Weak, reset during OnProfileManagerDestroying.
  raw_ptr<ProfileManager> profile_manager_ = nullptr;

  // Map from extension id to the state for that app.
  std::map<std::string, std::unique_ptr<AppState>> apps_;

  // The avatar menu instance used by all app shims.
  std::unique_ptr<AvatarMenu> avatar_menu_;

  // Requests for MacNotificationProviders that can't be connected to the
  // correct app shim process right away get added to this receiver set
  // instead. This is needed because higher level notifications code currently
  // always expects to get a connected MacNotificationProvider remote.
  mojo::ReceiverSet<mac_notifications::mojom::MacNotificationProvider>
      dummy_notification_provider_receivers_;

  // Notification actions from all app shims are routed through these receivers
  // and this class to make sure notification actions can be handled even if the
  // browser process has never tried to connect to the notification service
  // in an app shim.
  mojo::ReceiverSet<mac_notifications::mojom::MacNotificationActionHandler,
                    webapps::AppId>
      notification_action_handler_receivers_;

  // This contains `AppShimHostBootstrap` instances, keyed by the `ReceiverId`
  // for the corresponding `MacNotificationActionHandler` receiver in
  // `notification_action_handler_receivers_`, for app shims that were launched
  // by the OS to handle notification actions.
  std::map<mojo::ReceiverId, std::unique_ptr<AppShimHostBootstrap>>
      bootstraps_pending_notification_actions_;

  // Set in some tests to short-circuit ShowNotificationPermissionRequest.
  std::optional<mac_notifications::mojom::RequestPermissionResult>
      notification_permission_result_for_testing_;

  raw_ptr<AppShimObserver> app_shim_observer_ = nullptr;

  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
      profile_observation_{this};

  base::WeakPtrFactory<AppShimManager> weak_factory_;
};

}  // namespace apps

#endif  // CHROME_BROWSER_APPS_APP_SHIM_APP_SHIM_MANAGER_MAC_H_