| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 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_ANDROID_DATAUSAGE_EXTERNAL_DATA_USE_OBSERVER_H_ | |
| 6 #define CHROME_BROWSER_ANDROID_DATAUSAGE_EXTERNAL_DATA_USE_OBSERVER_H_ | |
| 7 | |
| 8 #include <jni.h> | |
| 9 #include <stdint.h> | |
| 10 | |
| 11 #include <string> | |
| 12 #include <unordered_map> | |
| 13 #include <vector> | |
| 14 | |
| 15 #include "base/android/jni_array.h" | |
| 16 #include "base/android/scoped_java_ref.h" | |
| 17 #include "base/gtest_prod_util.h" | |
| 18 #include "base/macros.h" | |
| 19 #include "base/memory/ref_counted.h" | |
| 20 #include "base/memory/scoped_vector.h" | |
| 21 #include "base/memory/weak_ptr.h" | |
| 22 #include "base/single_thread_task_runner.h" | |
| 23 #include "base/thread_task_runner_handle.h" | |
| 24 #include "base/threading/thread_checker.h" | |
| 25 #include "base/time/time.h" | |
| 26 #include "components/data_usage/core/data_use_aggregator.h" | |
| 27 #include "net/base/network_change_notifier.h" | |
| 28 | |
| 29 class GURL; | |
| 30 | |
| 31 namespace data_usage { | |
| 32 struct DataUse; | |
| 33 } | |
| 34 | |
| 35 namespace re2 { | |
| 36 class RE2; | |
| 37 } | |
| 38 | |
| 39 namespace chrome { | |
| 40 | |
| 41 namespace android { | |
| 42 | |
| 43 // This class allows platform APIs that are external to Chromium to observe how | |
| 44 // much data is used by Chromium on the current Android device. It creates and | |
| 45 // owns a Java listener object that is notified of the data usage observations | |
| 46 // of Chromium. This class receives regular expressions from the Java listener | |
| 47 // object. It also registers as a data use observer with DataUseAggregator, | |
| 48 // filters the received observations by applying the regex matching to the URLs | |
| 49 // of the requests, and notifies the filtered data use to the Java listener. The | |
| 50 // Java object in turn may notify the platform APIs of the data usage | |
| 51 // observations. | |
| 52 // TODO(tbansal): Create an inner class that manages the UI and IO threads. | |
| 53 class ExternalDataUseObserver : public data_usage::DataUseAggregator::Observer { | |
| 54 public: | |
| 55 ExternalDataUseObserver( | |
| 56 data_usage::DataUseAggregator* data_use_aggregator, | |
| 57 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner, | |
| 58 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner); | |
| 59 ~ExternalDataUseObserver() override; | |
| 60 | |
| 61 // Called by Java when new matching rules have been fetched. This may be | |
| 62 // called on a different thread. |app_package_name| is the package name of | |
| 63 // the app that should be matched. |domain_path_regex| is the regex to be used | |
| 64 // for matching URLs. |label| is the label that must be applied to data | |
| 65 // reports corresponding to the matching rule, and must | |
| 66 // uniquely identify the matching rule. Each element in |label| must have | |
| 67 // non-zero length. The three vectors should have equal length. The vectors | |
| 68 // may be empty which implies that no matching rules are active. Must be | |
| 69 // called on UI thread. | |
| 70 void FetchMatchingRulesCallback( | |
| 71 JNIEnv* env, | |
| 72 jobject obj, | |
| 73 const base::android::JavaParamRef<jobjectArray>& app_package_name, | |
| 74 const base::android::JavaParamRef<jobjectArray>& domain_path_regex, | |
| 75 const base::android::JavaParamRef<jobjectArray>& label); | |
| 76 | |
| 77 // Called by Java when the reporting of data usage has finished. This may be | |
| 78 // called on a different thread. |success| is true if the request was | |
| 79 // successfully submitted to the external data use observer by Java. Must be | |
| 80 // called on UI thread. | |
| 81 void OnReportDataUseDone(JNIEnv* env, jobject obj, bool success); | |
| 82 | |
| 83 private: | |
| 84 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, SingleRegex); | |
| 85 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, TwoRegex); | |
| 86 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, MultipleRegex); | |
| 87 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, ChangeRegex); | |
| 88 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, | |
| 89 AtMostOneDataUseSubmitRequest); | |
| 90 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, MultipleMatchingRules); | |
| 91 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, ReportsMergedCorrectly); | |
| 92 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, | |
| 93 TimestampsMergedCorrectly); | |
| 94 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, HashFunction); | |
| 95 FRIEND_TEST_ALL_PREFIXES(ExternalDataUseObserverTest, BufferSize); | |
| 96 | |
| 97 // DataUseReportKey is a unique identifier for a data use report. | |
| 98 struct DataUseReportKey { | |
| 99 DataUseReportKey(const std::string& label, | |
| 100 net::NetworkChangeNotifier::ConnectionType connection_type, | |
| 101 const std::string& mcc_mnc) | |
| 102 : label(label), connection_type(connection_type), mcc_mnc(mcc_mnc) {} | |
| 103 | |
| 104 DataUseReportKey(const DataUseReportKey& other) | |
| 105 : label(other.label), | |
| 106 connection_type(other.connection_type), | |
| 107 mcc_mnc(other.mcc_mnc) {} | |
| 108 | |
| 109 bool operator==(const DataUseReportKey& other) const { | |
| 110 return (label == other.label && | |
| 111 connection_type == other.connection_type && | |
| 112 mcc_mnc == other.mcc_mnc); | |
| 113 } | |
| 114 | |
| 115 virtual ~DataUseReportKey() {} | |
| 116 | |
| 117 // Label provided by the matching rules. | |
| 118 const std::string label; | |
| 119 | |
| 120 // Type of network used by the request. | |
| 121 const net::NetworkChangeNotifier::ConnectionType connection_type; | |
| 122 | |
| 123 // mcc_mnc operator of the provider of the SIM as obtained from | |
| 124 // TelephonyManager#getNetworkOperator() Java API in Android. | |
| 125 const std::string mcc_mnc; | |
| 126 }; | |
| 127 | |
| 128 // DataUseReport is paired with a DataUseReportKey object. DataUseReport | |
| 129 // contains the bytes send/received during a specific interval. Only the bytes | |
| 130 // from the data use reports that have the |label|, |connection_type|, and | |
| 131 // |mcc_mnc| specified in the corresponding DataUseReportKey object are | |
| 132 // counted in the DataUseReport. | |
| 133 struct DataUseReport { | |
| 134 // |start_time| and |end_time| are the start and end timestamps (in UTC | |
| 135 // since the standard Java epoch of 1970-01-01 00:00:00) of the interval | |
| 136 // that this data report covers. |bytes_downloaded| and |bytes_uploaded| are | |
| 137 // the total bytes received and send during this interval. | |
| 138 DataUseReport(const base::Time& start_time, | |
| 139 const base::Time& end_time, | |
| 140 int64_t bytes_downloaded, | |
| 141 int64_t bytes_uploaded) | |
| 142 : start_time(start_time), | |
| 143 end_time(end_time), | |
| 144 bytes_downloaded(bytes_downloaded), | |
| 145 bytes_uploaded(bytes_uploaded) {} | |
| 146 | |
| 147 virtual ~DataUseReport() {} | |
| 148 | |
| 149 // Start time of |this| data report (in UTC since the standard Java epoch of | |
| 150 // 1970-01-01 00:00:00). | |
| 151 const base::Time start_time; | |
| 152 | |
| 153 // End time of |this| data report (in UTC since the standard Java epoch of | |
| 154 // 1970-01-01 00:00:00) | |
| 155 const base::Time end_time; | |
| 156 | |
| 157 // Number of bytes downloaded and uploaded by Chromium from |start_time| to | |
| 158 // |end_time|. | |
| 159 const int64_t bytes_downloaded; | |
| 160 const int64_t bytes_uploaded; | |
| 161 }; | |
| 162 | |
| 163 // Class that implements hash operator on DataUseReportKey. | |
| 164 class DataUseReportKeyHash { | |
| 165 public: | |
| 166 // A simple heuristical hash function that satisifes the property that two | |
| 167 // equal data structures have the same hash value. The hash is computed by | |
| 168 // hashing individual variables and combining them using prime numbers. | |
| 169 // Prime numbers are used for multiplication because the number of buckets | |
| 170 // used by map is always an even number. Using a prime number ensures that | |
| 171 // for two different DataUseReportKey objects (say |j| and |k|), if the | |
| 172 // hash value of |k.label| is equal to hash value of |j.mcc_mnc|, then |j| | |
| 173 // and |k| map to different buckets. Large prime numbers are used so that | |
| 174 // hash value is spread over a larger range. | |
| 175 size_t operator()(const DataUseReportKey& k) const { | |
| 176 std::hash<std::string> hash_function; | |
| 177 size_t hash = 1; | |
| 178 hash = hash * 23 + hash_function(k.label); | |
| 179 hash = hash * 43 + k.connection_type; | |
| 180 hash = hash * 83 + hash_function(k.mcc_mnc); | |
| 181 return hash; | |
| 182 } | |
| 183 }; | |
| 184 | |
| 185 typedef std::unordered_map<DataUseReportKey, | |
| 186 DataUseReport, | |
| 187 DataUseReportKeyHash> DataUseReports; | |
| 188 | |
| 189 // Stores the matching rules. | |
| 190 class MatchingRule { | |
| 191 public: | |
| 192 MatchingRule(const std::string& app_package_name, | |
| 193 scoped_ptr<re2::RE2> pattern, | |
| 194 const std::string& label); | |
| 195 ~MatchingRule(); | |
| 196 | |
| 197 const re2::RE2* pattern() const; | |
| 198 const std::string& label() const; | |
| 199 | |
| 200 private: | |
| 201 // Package name of the app that should be matched. | |
| 202 const std::string app_package_name_; | |
| 203 | |
| 204 // RE2 pattern to match against URLs. | |
| 205 scoped_ptr<re2::RE2> pattern_; | |
| 206 | |
| 207 // Opaque label that uniquely identifies this matching rule. | |
| 208 const std::string label_; | |
| 209 | |
| 210 DISALLOW_COPY_AND_ASSIGN(MatchingRule); | |
| 211 }; | |
| 212 | |
| 213 // Maximum buffer size. If an entry needs to be added to the buffer that has | |
| 214 // size |kMaxBufferSize|, then the oldest entry will be removed. | |
| 215 static const size_t kMaxBufferSize = 100; | |
| 216 | |
| 217 // Creates Java object. Must be called on the UI thread. | |
| 218 void CreateJavaObjectOnUIThread(); | |
| 219 | |
| 220 // data_usage::DataUseAggregator::Observer implementation: | |
| 221 void OnDataUse(const std::vector<const data_usage::DataUse*>& | |
| 222 data_use_sequence) override; | |
| 223 | |
| 224 // Fetches matching rules from Java. Must be called on the UI thread. Returns | |
| 225 // result asynchronously on UI thread via FetchMatchingRulesCallback. | |
| 226 void FetchMatchingRulesOnUIThread() const; | |
| 227 | |
| 228 // Called by FetchMatchingRulesCallback on IO thread when new matching rules | |
| 229 // Adds |data_use| to buffered reports. |data_use| is the data use report | |
| 230 // received from DataUseAggregator. |data_use| should not be null. |label| is | |
| 231 // a non-empty label that applies to |data_use|. |start_time| and |end_time| | |
| 232 // are the start, and end times of the interval during which bytes reported in | |
| 233 // |data_use| went over the network. | |
| 234 void BufferDataUseReport(const data_usage::DataUse* data_use, | |
| 235 const std::string& label, | |
| 236 const base::Time& start_time, | |
| 237 const base::Time& end_time); | |
| 238 | |
| 239 // Submits the first data report among the buffered data reports in | |
| 240 // |buffered_data_reports_|. Since an unordered_map is used to buffer the | |
| 241 // reports, the order of reports may change. The reports are buffered in an | |
| 242 // arbitrary order and there are no guarantees that the next report to be | |
| 243 // submitted is the oldest one buffered. | |
| 244 void SubmitBufferedDataUseReport(); | |
| 245 | |
| 246 // Called by |FetchMatchingRulesCallback| on IO thread when new matching rules | |
| 247 // have been fetched. | |
| 248 void FetchMatchingRulesCallbackOnIOThread( | |
| 249 const std::vector<std::string>& app_package_name, | |
| 250 const std::vector<std::string>& domain_path_regex, | |
| 251 const std::vector<std::string>& label); | |
| 252 | |
| 253 // Reports data use to Java. Must be called on the UI thread. Returns | |
| 254 // result asynchronously on UI thread via OnReportDataUseDone. | |
| 255 void ReportDataUseOnUIThread(const DataUseReportKey& key, | |
| 256 const DataUseReport& report) const; | |
| 257 | |
| 258 // Called by OnReportDataUseDone on IO thread when a data use report has | |
| 259 // been submitted. | |
| 260 void OnReportDataUseDoneOnIOThread(bool success); | |
| 261 | |
| 262 // Called by FetchMatchingRulesCallbackIO to register multiple | |
| 263 // case-insensitive regular expressions. If the url of the data use request | |
| 264 // matches any of the regular expression, the observation is passed to the | |
| 265 // Java listener. | |
| 266 void RegisterURLRegexes(const std::vector<std::string>& app_package_name, | |
| 267 const std::vector<std::string>& domain_path_regex, | |
| 268 const std::vector<std::string>& label); | |
| 269 | |
| 270 // Returns true if the |gurl| matches the registered regular expressions. | |
| 271 // |label| must not be null. If a match is found, the |label| is set to the | |
| 272 // matching rule's label. | |
| 273 bool Matches(const GURL& gurl, std::string* label) const; | |
| 274 | |
| 275 // Return the weak pointer to |this| to be used on IO and UI thread, | |
| 276 // respectively. | |
| 277 base::WeakPtr<ExternalDataUseObserver> GetIOWeakPtr(); | |
| 278 base::WeakPtr<ExternalDataUseObserver> GetUIWeakPtr(); | |
| 279 | |
| 280 // Aggregator that sends data use observations to |this|. | |
| 281 data_usage::DataUseAggregator* data_use_aggregator_; | |
| 282 | |
| 283 // Java listener that provides regular expressions to |this|. The regular | |
| 284 // expressions are applied to the request URLs, and filtered data use is | |
| 285 // notified to |j_external_data_use_observer_|. | |
| 286 base::android::ScopedJavaGlobalRef<jobject> j_external_data_use_observer_; | |
| 287 | |
| 288 // True if callback from |FetchMatchingRulesCallback| is currently pending. | |
| 289 bool matching_rules_fetch_pending_; | |
| 290 | |
| 291 // True if callback from |SubmitDataUseReportCallback| is currently pending. | |
| 292 bool submit_data_report_pending_; | |
| 293 | |
| 294 // Contains matching rules. | |
| 295 ScopedVector<MatchingRule> matching_rules_; | |
| 296 | |
| 297 // Buffered data reports that need to be submitted to the Java data use | |
| 298 // observer. | |
| 299 DataUseReports buffered_data_reports_; | |
| 300 | |
| 301 // True if |this| is currently registered as a data use observer. | |
| 302 bool registered_as_observer_; | |
| 303 | |
| 304 // |io_task_runner_| accesses ExternalDataUseObserver members on IO thread. | |
| 305 scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; | |
| 306 | |
| 307 // |ui_task_runner_| is used to call Java code on UI thread. This ensures | |
| 308 // that Java code is safely called only on a single thread, and eliminates | |
| 309 // the need for locks in Java. | |
| 310 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_; | |
| 311 | |
| 312 // Time when the data use reports were last received from DataUseAggregator. | |
| 313 base::Time previous_report_time_; | |
| 314 | |
| 315 base::ThreadChecker thread_checker_; | |
| 316 | |
| 317 // |io_weak_factory_| and |ui_weak_factory_| are used for posting tasks on the | |
| 318 // IO and UI thread, respectively. | |
| 319 base::WeakPtrFactory<ExternalDataUseObserver> io_weak_factory_; | |
| 320 base::WeakPtrFactory<ExternalDataUseObserver> ui_weak_factory_; | |
| 321 | |
| 322 DISALLOW_COPY_AND_ASSIGN(ExternalDataUseObserver); | |
| 323 }; | |
| 324 | |
| 325 bool RegisterExternalDataUseObserver(JNIEnv* env); | |
| 326 | |
| 327 } // namespace android | |
| 328 | |
| 329 } // namespace chrome | |
| 330 | |
| 331 #endif // CHROME_BROWSER_ANDROID_DATAUSAGE_EXTERNAL_DATA_USE_OBSERVER_H_ | |
| OLD | NEW |