File: app_capability_access_cache.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 6,122,156 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 (201 lines) | stat: -rw-r--r-- 8,752 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
// 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 COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_CAPABILITY_ACCESS_CACHE_H_
#define COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_CAPABILITY_ACCESS_CACHE_H_

#include <map>
#include <set>
#include <vector>

#include "base/component_export.h"
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/observer_list_types.h"
#include "base/sequence_checker.h"
#include "components/account_id/account_id.h"
#include "components/services/app_service/public/cpp/capability_access.h"
#include "components/services/app_service/public/cpp/capability_access_update.h"

namespace apps {

// An in-memory cache of app capability accesses, recording which apps are using
// sensitive capabilities like camera or microphone. Can be queried
// synchronously for information about current capability usage, and can be
// observed to receive updates about changes to capability usage.
//
// AppServiceProxy sees a stream of `apps::CapabilityAccessPtr` "deltas", or
// changes in capability access, received from publishers. This cache stores the
// "sum" of those previous deltas. When a new delta is received, observers are
// presented with an `apps:::CapabilityAccessUpdate` containing information
// about what has changed, and then the new delta is "added" to the stored
// state.
//
// This class is not thread-safe.
class COMPONENT_EXPORT(APP_UPDATE) AppCapabilityAccessCache {
 public:
  class COMPONENT_EXPORT(APP_UPDATE) Observer : public base::CheckedObserver {
   public:
    // Called whenever AppCapabilityAccessCache receives a capability access
    // update for any app. `update` exposes the latest capability usage and
    // what has changed in this update (as per the docs on
    // `apps::CapabilityAccessUpdate`). The `update` argument shouldn't be
    // accessed after OnCapabilityAccessUpdate returns.
    virtual void OnCapabilityAccessUpdate(
        const CapabilityAccessUpdate& update) = 0;

    // Called when the AppCapabilityAccessCache object (the thing that this
    // observer observes) will be destroyed. In response, the observer, |this|,
    // should call "cache->RemoveObserver(this)", whether directly or indirectly
    // (e.g. via base::ScopedObservation::Reset).
    virtual void OnAppCapabilityAccessCacheWillBeDestroyed(
        AppCapabilityAccessCache* cache) = 0;

   protected:
    ~Observer() override;
  };

  AppCapabilityAccessCache();
  ~AppCapabilityAccessCache();

  void AddObserver(Observer* observer);
  void RemoveObserver(Observer* observer);

  void SetAccountId(const AccountId& account_id);

  // Returns app ids which are accessing the camera.
  std::set<std::string> GetAppsAccessingCamera();

  // Returns app ids which are accessing the microphone.
  std::set<std::string> GetAppsAccessingMicrophone();

  // Returns app ids which are accessing any capability.
  std::set<std::string> GetAppsAccessingCapabilities();

  // Notifies all observers of state-and-delta CapabilityAccessUpdate's (the
  // state comes from the internal cache, the delta comes from the argument) and
  // then merges the cached states with the deltas.
  //
  // Notification and merging might be delayed until after OnCapabilityAccesses
  // returns. For example, suppose that the initial set of states is (a0, b0,
  // c0) for three app_id's ("a", "b", "c"). Now suppose OnCapabilityAccesses is
  // called with two updates (b1, c1), and when notified of b1, an observer
  // calls OnCapabilityAccesses again with (c2, d2). The c1 delta should be
  // processed before the c2 delta, as it was sent first: c2 should be merged
  // (with "newest wins" semantics) onto c1 and not vice versa. This means that
  // processing c2 (scheduled by the second OnCapabilityAccesses call) should
  // wait until the first OnCapabilityAccesses call has finished processing b1
  // (and then c1), which means that processing c2 is delayed until after the
  // second OnCapabilityAccesses call returns.
  //
  // The callee will consume the deltas. An apps::CapabilityAccessPtr has
  // the ownership semantics of a unique_ptr, and will be deleted when out of
  // scope. The caller presumably calls OnCapabilityAccesses(std::move(deltas)).
  void OnCapabilityAccesses(std::vector<CapabilityAccessPtr> deltas);

  // Calls f, a void-returning function whose arguments are (const
  // apps::CapabilityAccessUpdate&), on each app in AppCapabilityAccessCache.
  //
  // f's argument is an apps::CapabilityAccessUpdate instead of an
  // apps::CapabilityAccessPtr so that callers can more easily share code
  // with Observer::OnCapabilityAccessUpdate (which also takes an
  // apps::CapabilityAccessUpdate), and an apps::CapabilityAccessUpdate also has
  // a StateIsNull method.
  //
  // The apps::CapabilityAccessUpdate argument to f shouldn't be accessed after
  // f returns.
  //
  // f must be synchronous, and if it asynchronously calls ForEachApp again,
  // it's not guaranteed to see a consistent state.
  template <typename FunctionType>
  void ForEachApp(FunctionType f) {
    DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);

    for (const auto& s_iter : states_) {
      const CapabilityAccess* state = s_iter.second.get();

      auto d_iter = deltas_in_progress_.find(s_iter.first);
      const CapabilityAccess* delta =
          (d_iter != deltas_in_progress_.end()) ? d_iter->second : nullptr;

      f(CapabilityAccessUpdate(state, delta, account_id_));
    }

    for (const auto& d_iter : deltas_in_progress_) {
      const CapabilityAccess* delta = d_iter.second;

      auto s_iter = states_.find(d_iter.first);
      if (s_iter != states_.end()) {
        continue;
      }

      f(CapabilityAccessUpdate(nullptr, delta, account_id_));
    }
  }

  // Calls f, a void-returning function whose arguments are (const
  // apps::CapabilityAccessUpdate&), on the app in AppCapabilityAccessCache with
  // the given app_id. It will return true (and call f) if there is such an app,
  // otherwise it will return false (and not call f). The CapabilityAccessUpdate
  // argument to f has the same semantics as for ForEachApp, above.
  //
  // f must be synchronous, and if it asynchronously calls ForEachApp again,
  // it's not guaranteed to see a consistent state.
  template <typename FunctionType>
  bool ForOneApp(const std::string& app_id, FunctionType f) {
    DCHECK_CALLED_ON_VALID_SEQUENCE(my_sequence_checker_);

    auto s_iter = states_.find(app_id);
    const CapabilityAccess* state =
        (s_iter != states_.end()) ? s_iter->second.get() : nullptr;

    auto d_iter = deltas_in_progress_.find(app_id);
    const CapabilityAccess* delta =
        (d_iter != deltas_in_progress_.end()) ? d_iter->second : nullptr;

    if (state || delta) {
      f(CapabilityAccessUpdate(state, delta, account_id_));
      return true;
    }
    return false;
  }

 private:
  void DoOnCapabilityAccesses(std::vector<CapabilityAccessPtr> deltas);

  base::ObserverList<Observer> observers_;

  // Maps from app_id to the latest state: the "sum" of all previous deltas.
  std::map<std::string, CapabilityAccessPtr> states_;

  // Track the deltas being processed or are about to be processed by
  // OnCapabilityAccesses. They are separate to manage the "notification and
  // merging might be delayed until after OnCapabilityAccesses returns" concern
  // described above.
  //
  // OnCapabilityAccesses calls DoOnCapabilityAccesses zero or more times. If
  // we're nested, so that there's multiple OnCapabilityAccesses call to this
  // AppCapabilityAccessCache in the call stack, the deeper OnCapabilityAccesses
  // call simply adds work to deltas_pending_ and returns without calling
  // DoOnCapabilityAccesses. If we're not nested, OnCapabilityAccesses calls
  // DoOnCapabilityAccesses one or more times; "more times" happens if
  // DoOnAccesses notifying observers leads to more OnCapabilityAccesses calls
  // that enqueue deltas_pending_ work. The deltas_in_progress_ map (keyed by
  // app_id) contains those deltas being considered by DoOnCapabilityAccesses.
  //
  // Nested OnCapabilityAccesses calls are expected to be rare (but still dealt
  // with sensibly). In the typical case, OnCapabilityAccesses should call
  // DoOnCapabilityAccesses exactly once, and deltas_pending_ will stay empty.
  std::map<std::string, raw_ptr<CapabilityAccess, CtnExperimental>>
      deltas_in_progress_;
  std::vector<CapabilityAccessPtr> deltas_pending_;

  AccountId account_id_;

  SEQUENCE_CHECKER(my_sequence_checker_);
};

}  // namespace apps

#endif  // COMPONENTS_SERVICES_APP_SERVICE_PUBLIC_CPP_APP_CAPABILITY_ACCESS_CACHE_H_