1 // Copyright 2018 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_RESOURCE_COORDINATOR_DECISION_DETAILS_H_ 6 #define CHROME_BROWSER_RESOURCE_COORDINATOR_DECISION_DETAILS_H_ 7 8 #include <string> 9 #include <vector> 10 11 #include "base/macros.h" 12 13 namespace ukm { 14 namespace builders { 15 class TabManager_LifecycleStateChange; 16 } 17 } // namespace ukm 18 19 namespace resource_coordinator { 20 21 // An enumeration of reasons why a particular intervention or lifecycle state 22 // changes can be denied. This is a superset of all failure reasons that can 23 // apply for any particular intervention. New reasons can freely be added to 24 // this enum as necessary, but UKM plumbing and string conversion needs to be 25 // maintained as well. 26 enum class DecisionFailureReason : int32_t { 27 // An invalid failure reason. This must remain first. 28 INVALID = -1, 29 // The browser was opted out of the intervention via enterprise policy. 30 LIFECYCLES_ENTERPRISE_POLICY_OPT_OUT, 31 // A frame on the page opted itself out of the intervention via origin trial. 32 ORIGIN_TRIAL_OPT_OUT, 33 // The origin was opted out of the intervention in the global disallowlist. 34 GLOBAL_DISALLOWLIST, 35 // The local heuristic opted the origin out of the intervention due to its use 36 // of audio while in the background. 37 HEURISTIC_AUDIO, 38 // The local heuristic opted the origin out of the intervention due to its use 39 // of favicon updates while in the background. 40 HEURISTIC_FAVICON, 41 // The local heuristic is temporarily opting the origin out of the 42 // intervention due to a lack of sufficient observation time. 43 HEURISTIC_INSUFFICIENT_OBSERVATION, 44 // The local heuristic opted the origin out of the intervention due to its use 45 // of title updates while in the background. 46 HEURISTIC_TITLE, 47 // The tab is opted out of the intervention as it is currently capturing user 48 // media (webcam, microphone, etc). 49 LIVE_STATE_CAPTURING, 50 // The tab is opted out of the intervention by an extension. 51 LIVE_STATE_EXTENSION_DISALLOWED, 52 // The tab is opted out of the intervention as it contains text form entry. 53 LIVE_STATE_FORM_ENTRY, 54 // The tab is opted out of the intervention as it is currently hosting a PDF. 55 LIVE_STATE_IS_PDF, 56 // The tab is opted out of the intervention as it is currently being mirrored 57 // (casting, etc). 58 LIVE_STATE_MIRRORING, 59 // The tab is opted out of the intervention as it is currently playing audio. 60 LIVE_STATE_PLAYING_AUDIO, 61 // The tab is opted out of the intervention as it is currently using 62 // WebSockets. 63 // NOTE: This heuristic isn't used in the freezing/discarding interventions. 64 LIVE_STATE_USING_WEB_SOCKETS, 65 // The tab is opted out of the intervention as it is currently WebUSB. 66 LIVE_STATE_USING_WEB_USB, 67 // The tab is opted out of the intervention as it is currently visible. 68 LIVE_STATE_VISIBLE, 69 // The tab is opted out of the intervention as it's currently using DevTools. 70 LIVE_STATE_DEVTOOLS_OPEN, 71 // The tab is opted out of the intervention as it's currently capturing a 72 // window or screen. 73 LIVE_STATE_DESKTOP_CAPTURE, 74 // This tab is sharing its BrowsingInstance with another tab, and so could 75 // want to communicate with it. 76 LIVE_STATE_SHARING_BROWSING_INSTANCE, 77 // The tab is opted out of the intervention as it's currently connected to a 78 // bluetooth device. 79 LIVE_STATE_USING_BLUETOOTH, 80 // The tab is opted out of the intervention as it's currently holding at least 81 // one WebLock. 82 LIVE_STATE_USING_WEBLOCK, 83 // The tab is opted out of the intervention as it's currently holding at least 84 // one IndexedDB lock. 85 LIVE_STATE_USING_INDEXEDDB_LOCK, 86 // The tab is opted out of the intervention as it has the permission to use 87 // notifications. 88 LIVE_STATE_HAS_NOTIFICATIONS_PERMISSION, 89 // The tab is a standalone desktop PWA window. 90 LIVE_WEB_APP, 91 // This must remain last. 92 MAX, 93 }; 94 95 // An enumeration of reasons why a particular intervention or lifecycle state 96 // change can be approved. The fact that no "live state" failures are blocking 97 // the intervention is implicit, and doesn't need to be explicitly encoded. 98 enum class DecisionSuccessReason : int32_t { 99 // An invalid failure reason. This must remain first. 100 INVALID = -1, 101 // A frame on the page opted itself in the intervention via origin trial. 102 ORIGIN_TRIAL_OPT_IN, 103 // The origin was opted into the intervention via the global allowlist. 104 GLOBAL_ALLOWLIST, 105 // The origin has been observed to be safe for the intervention using local 106 // database observations. 107 HEURISTIC_OBSERVED_TO_BE_SAFE, 108 // This must remain last. 109 MAX, 110 }; 111 112 // Helper function for converting a reason to a string representation. 113 const char* ToString(DecisionFailureReason failure_reason); 114 const char* ToString(DecisionSuccessReason success_reason); 115 116 // Describes the detailed reasons why a particular intervention decision was 117 // made. This is populated by the various policy bits of policy logic that 118 // decide whether a particular intervention or lifecycle state transition can be 119 // performed. It can populate various related UKM builders and also be converted 120 // to a collection of user readable strings for the purposes of displaying in 121 // in web UI. 122 // 123 // A decision can contain multiple reasons for success or failure, and policy 124 // allows some success reasons to override some failure reasons and vice versa. 125 // The first reason posted to this object determines whether or not the overall 126 // outcome is positive or negative. It is assumed that reasons are posted in 127 // order of decreasing priority. 128 // 129 // For logging and inspection it is useful to know of all possible failure 130 // reasons blocking a success. Similarly, it is interesting to know of all of 131 // the possible success reasons blocking a failure. To this end, policy logic 132 // should continue populating the decision with details until is has "toggled". 133 // That is, a success reason has followed a chain of failures or vice versa. 134 // The "toggling" of the decision chain is indicated by the return value from 135 // AddReason. This allows writing code like the following: 136 // 137 // bool DecideIfCanDoSomething(DecisionDetails* details) { 138 // if (some_condition_is_false) { 139 // if (details->AddReason(kSomeFailureReason)) 140 // return details->IsPositive(); 141 // } 142 // if (some_other_condition) { 143 // if (details->AddReason(kSomeOtherFailureReason)) 144 // return details->IsPositive(); 145 // } 146 // ... 147 // } 148 class DecisionDetails { 149 public: 150 // A union of success/failure reasons. This is allowed to be copied in order 151 // to be compatible with STL containers. 152 class Reason { 153 public: 154 Reason(); 155 explicit Reason(DecisionSuccessReason success_reason); 156 explicit Reason(DecisionFailureReason failure_reason); 157 Reason(const Reason& rhs); 158 ~Reason(); 159 160 Reason& operator=(const Reason& rhs); 161 162 bool IsValid() const; 163 bool IsSuccess() const; 164 bool IsFailure() const; 165 DecisionSuccessReason success_reason() const; 166 DecisionFailureReason failure_reason() const; 167 168 const char* ToString() const; 169 170 bool operator==(const Reason& rhs) const; 171 bool operator!=(const Reason& rhs) const; 172 173 private: 174 DecisionSuccessReason success_reason_; 175 DecisionFailureReason failure_reason_; 176 }; 177 178 DecisionDetails(); 179 ~DecisionDetails(); 180 181 // Allow move assignment. 182 DecisionDetails& operator=(DecisionDetails&& rhs); 183 184 // Adds a success or failure reason. Returns true if the chain of reasons has 185 // "toggled", false otherwise. 186 bool AddReason(const Reason& reason); 187 bool AddReason(DecisionFailureReason failure_reason); 188 bool AddReason(DecisionSuccessReason success_reason); 189 190 // Returns the outcome of the decision. This is implicit from the reasons that 191 // have been posted to this object. 192 bool IsPositive() const; 193 194 // Returns the main success reason. This is only valid to call if IsPositive 195 // is true. 196 DecisionSuccessReason SuccessReason() const; 197 198 // Returns the main failure reason. This is only valid to call if IsPositive 199 // is false. 200 DecisionFailureReason FailureReason() const; 201 202 // Returns the full vector of reasons. reasons()203 const std::vector<Reason>& reasons() const { return reasons_; } 204 205 // Returns whether or not the chain of reasons has toggled. toggled()206 bool toggled() const { return toggled_; } 207 208 // Populates the provided "TabManager.LifecycleStateChange" UKM builder with 209 // information from this object. 210 void Populate(ukm::builders::TabManager_LifecycleStateChange* ukm) const; 211 212 // Returns a collection of failure reason strings, from most important failure 213 // reason to least important. This is empty if the outcome is positive, and 214 // will only be populated with failure reasons that are not overridden by any 215 // success reasons. 216 std::vector<std::string> GetFailureReasonStrings() const; 217 218 void Clear(); 219 220 private: 221 bool CheckIfToggled(); 222 223 // This is true if the vector of success reasons has "toggled" from all 224 // failures to some successes, or vice versa. Continuing to collect additional 225 // reasons after this toggle isn't very informative. 226 bool toggled_; 227 std::vector<Reason> reasons_; 228 229 DISALLOW_COPY_AND_ASSIGN(DecisionDetails); 230 }; 231 232 } // namespace resource_coordinator 233 234 #endif // CHROME_BROWSER_RESOURCE_COORDINATOR_DECISION_DETAILS_H_ 235