| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/data_usage/data_use_tab_model.h" | 5 #include "chrome/browser/android/data_usage/data_use_tab_model.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "base/single_thread_task_runner.h" |
| 8 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 9 #include "base/time/time.h" | 10 #include "base/time/time.h" |
| 10 #include "chrome/browser/android/data_usage/external_data_use_observer.h" | 11 #include "chrome/browser/android/data_usage/external_data_use_observer.h" |
| 11 #include "chrome/browser/android/data_usage/tab_data_use_entry.h" | 12 #include "components/data_usage/core/data_use.h" |
| 12 #include "components/variations/variations_associated_data.h" | 13 #include "components/variations/variations_associated_data.h" |
| 13 | 14 |
| 14 namespace { | 15 namespace { |
| 15 | 16 |
| 16 // Indicates the default maximum number of tabs to maintain session information | 17 // Indicates the default maximum number of tabs to maintain session information |
| 17 // about. May be overridden by the field trial. | 18 // about. May be overridden by the field trial. |
| 18 const size_t kDefaultMaxTabEntries = 200; | 19 const size_t kDefaultMaxTabEntries = 200; |
| 19 | 20 |
| 20 const char kUMAExpiredInactiveTabEntryRemovalDurationSecondsHistogram[] = | 21 const char kUMAExpiredInactiveTabEntryRemovalDurationSecondsHistogram[] = |
| 21 "DataUse.TabModel.ExpiredInactiveTabEntryRemovalDuration"; | 22 "DataUse.TabModel.ExpiredInactiveTabEntryRemovalDuration"; |
| 22 const char kUMAExpiredActiveTabEntryRemovalDurationHoursHistogram[] = | 23 const char kUMAExpiredActiveTabEntryRemovalDurationHoursHistogram[] = |
| 23 "DataUse.TabModel.ExpiredActiveTabEntryRemovalDuration"; | 24 "DataUse.TabModel.ExpiredActiveTabEntryRemovalDuration"; |
| 24 const char kUMAUnexpiredTabEntryRemovalDurationMinutesHistogram[] = | 25 const char kUMAUnexpiredTabEntryRemovalDurationMinutesHistogram[] = |
| 25 "DataUse.TabModel.UnexpiredTabEntryRemovalDuration"; | 26 "DataUse.TabModel.UnexpiredTabEntryRemovalDuration"; |
| 26 | 27 |
| 27 // Returns true if |tab_id| is a valid tab ID. | 28 // Returns true if |tab_id| is a valid tab ID. |
| 28 bool IsValidTabID(int32_t tab_id) { | 29 bool IsValidTabID(SessionID::id_type tab_id) { |
| 29 return tab_id >= 0; | 30 return tab_id >= 0; |
| 30 } | 31 } |
| 31 | 32 |
| 32 // Returns various parameters from the values specified in the field trial. | 33 // Returns various parameters from the values specified in the field trial. |
| 33 size_t GetMaxTabEntries() { | 34 size_t GetMaxTabEntries() { |
| 34 size_t max_tab_entries = -1; | 35 size_t max_tab_entries = -1; |
| 35 std::string variation_value = variations::GetVariationParamValue( | 36 std::string variation_value = variations::GetVariationParamValue( |
| 36 chrome::android::ExternalDataUseObserver:: | 37 chrome::android::ExternalDataUseObserver:: |
| 37 kExternalDataUseObserverFieldTrial, | 38 kExternalDataUseObserverFieldTrial, |
| 38 "max_tab_entries"); | 39 "max_tab_entries"); |
| 39 if (!variation_value.empty() && | 40 if (!variation_value.empty() && |
| 40 base::StringToSizeT(variation_value, &max_tab_entries)) { | 41 base::StringToSizeT(variation_value, &max_tab_entries)) { |
| 41 return max_tab_entries; | 42 return max_tab_entries; |
| 42 } | 43 } |
| 43 return kDefaultMaxTabEntries; | 44 return kDefaultMaxTabEntries; |
| 44 } | 45 } |
| 45 | 46 |
| 46 } // namespace | 47 } // namespace |
| 47 | 48 |
| 48 namespace chrome { | 49 namespace chrome { |
| 49 | 50 |
| 50 namespace android { | 51 namespace android { |
| 51 | 52 |
| 52 DataUseTabModel::DataUseTabModel( | 53 DataUseTabModel::DataUseTabModel( |
| 53 const ExternalDataUseObserver* data_use_observer, | 54 const ExternalDataUseObserver* data_use_observer, |
| 54 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) | 55 scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner) |
| 55 : data_use_observer_(data_use_observer), | 56 : data_use_observer_(data_use_observer), |
| 56 observer_list_(new base::ObserverListThreadSafe<TabDataUseObserver>), | |
| 57 max_tab_entries_(GetMaxTabEntries()), | 57 max_tab_entries_(GetMaxTabEntries()), |
| 58 weak_factory_(this) {} | 58 ui_task_runner_(ui_task_runner), |
| 59 weak_factory_(this) { |
| 60 DCHECK(ui_task_runner_); |
| 61 } |
| 59 | 62 |
| 60 DataUseTabModel::~DataUseTabModel() { | 63 DataUseTabModel::~DataUseTabModel() { |
| 61 DCHECK(thread_checker_.CalledOnValidThread()); | 64 DCHECK(thread_checker_.CalledOnValidThread()); |
| 62 } | 65 } |
| 63 | 66 |
| 64 base::WeakPtr<DataUseTabModel> DataUseTabModel::GetWeakPtr() { | 67 base::WeakPtr<DataUseTabModel> DataUseTabModel::GetWeakPtr() { |
| 65 DCHECK(thread_checker_.CalledOnValidThread()); | 68 DCHECK(thread_checker_.CalledOnValidThread()); |
| 66 return weak_factory_.GetWeakPtr(); | 69 return weak_factory_.GetWeakPtr(); |
| 67 } | 70 } |
| 68 | 71 |
| 69 void DataUseTabModel::OnNavigationEvent(int32_t tab_id, | 72 void DataUseTabModel::OnNavigationEvent(SessionID::id_type tab_id, |
| 70 TransitionType transition, | 73 TransitionType transition, |
| 71 const GURL& url, | 74 const GURL& url, |
| 72 const std::string& package) { | 75 const std::string& package) { |
| 73 DCHECK(thread_checker_.CalledOnValidThread()); | 76 DCHECK(thread_checker_.CalledOnValidThread()); |
| 74 DCHECK(IsValidTabID(tab_id)); | 77 DCHECK(IsValidTabID(tab_id)); |
| 75 | 78 |
| 76 switch (transition) { | 79 switch (transition) { |
| 77 case TRANSITION_OMNIBOX_SEARCH: | 80 case TRANSITION_OMNIBOX_SEARCH: |
| 81 case TRANSITION_OMNIBOX_NAVIGATION: |
| 78 case TRANSITION_FROM_EXTERNAL_APP: { | 82 case TRANSITION_FROM_EXTERNAL_APP: { |
| 79 // Enter events. | 83 // Enter events. |
| 80 bool start_tracking = false; | 84 bool start_tracking = false; |
| 81 std::string label; | 85 std::string label; |
| 82 TabEntryMap::const_iterator tab_entry_iterator = | 86 TabEntryMap::const_iterator tab_entry_iterator = |
| 83 active_tabs_.find(tab_id); | 87 active_tabs_.find(tab_id); |
| 84 if (tab_entry_iterator != active_tabs_.end() && | 88 if (tab_entry_iterator != active_tabs_.end() && |
| 85 tab_entry_iterator->second.IsTrackingDataUse()) { | 89 tab_entry_iterator->second.IsTrackingDataUse()) { |
| 86 break; | 90 break; |
| 87 } | 91 } |
| 88 if (transition == TRANSITION_FROM_EXTERNAL_APP) { | 92 if (transition == TRANSITION_FROM_EXTERNAL_APP) { |
| 89 // Package name should match, for transitions from external app. | 93 // Package name should match, for transitions from external app. |
| 90 if (!package.empty() && | 94 if (!package.empty() && |
| 91 data_use_observer_->MatchesAppPackageName(package, &label)) { | 95 data_use_observer_->MatchesAppPackageName(package, &label)) { |
| 92 DCHECK(!label.empty()); | 96 DCHECK(!label.empty()); |
| 93 start_tracking = true; | 97 start_tracking = true; |
| 94 } | 98 } |
| 95 } | 99 } |
| 96 if (!start_tracking && !url.is_empty() && | 100 if (!start_tracking && !url.is_empty() && |
| 97 data_use_observer_->Matches(url, &label)) { | 101 data_use_observer_->Matches(url, &label)) { |
| 98 DCHECK(!label.empty()); | 102 DCHECK(!label.empty()); |
| 99 start_tracking = true; | 103 start_tracking = true; |
| 100 } | 104 } |
| 101 if (start_tracking) | 105 if (start_tracking) |
| 102 StartTrackingDataUse(tab_id, label); | 106 StartTrackingDataUse(tab_id, label); |
| 103 break; | 107 break; |
| 104 } | 108 } |
| 105 | 109 |
| 106 case TRANSITION_FROM_NAVSUGGEST: | |
| 107 case TRANSITION_OMNIBOX_NAVIGATION: | |
| 108 case TRANSITION_BOOKMARK: | 110 case TRANSITION_BOOKMARK: |
| 109 case TRANSITION_HISTORY_ITEM: | 111 case TRANSITION_HISTORY_ITEM: |
| 110 case TRANSITION_TO_EXTERNAL_APP: | |
| 111 // Exit events. | 112 // Exit events. |
| 112 EndTrackingDataUse(tab_id); | 113 EndTrackingDataUse(tab_id); |
| 113 break; | 114 break; |
| 114 | 115 |
| 115 default: | 116 default: |
| 116 NOTREACHED(); | 117 NOTREACHED(); |
| 117 break; | 118 break; |
| 118 } | 119 } |
| 119 } | 120 } |
| 120 | 121 |
| 121 void DataUseTabModel::OnTabCloseEvent(int32_t tab_id) { | 122 void DataUseTabModel::OnTabCloseEvent(SessionID::id_type tab_id) { |
| 122 DCHECK(thread_checker_.CalledOnValidThread()); | 123 DCHECK(thread_checker_.CalledOnValidThread()); |
| 123 DCHECK(IsValidTabID(tab_id)); | 124 DCHECK(IsValidTabID(tab_id)); |
| 124 | 125 |
| 125 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); | 126 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); |
| 126 if (tab_entry_iterator == active_tabs_.end()) | 127 if (tab_entry_iterator == active_tabs_.end()) |
| 127 return; | 128 return; |
| 128 | 129 |
| 129 TabDataUseEntry& tab_entry = tab_entry_iterator->second; | 130 TabDataUseEntry& tab_entry = tab_entry_iterator->second; |
| 130 if (tab_entry.IsTrackingDataUse()) | 131 if (tab_entry.IsTrackingDataUse()) |
| 131 tab_entry.EndTracking(); | 132 tab_entry.EndTracking(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 152 TabEntryMap::const_iterator tab_entry_iterator = | 153 TabEntryMap::const_iterator tab_entry_iterator = |
| 153 active_tabs_.find(data_use.tab_id); | 154 active_tabs_.find(data_use.tab_id); |
| 154 if (tab_entry_iterator != active_tabs_.end()) { | 155 if (tab_entry_iterator != active_tabs_.end()) { |
| 155 return tab_entry_iterator->second.GetLabel(data_use.request_start, | 156 return tab_entry_iterator->second.GetLabel(data_use.request_start, |
| 156 output_label); | 157 output_label); |
| 157 } | 158 } |
| 158 | 159 |
| 159 return false; // Tab session not found. | 160 return false; // Tab session not found. |
| 160 } | 161 } |
| 161 | 162 |
| 162 void DataUseTabModel::AddObserver(TabDataUseObserver* observer) { | 163 void DataUseTabModel::AddObserver( |
| 163 observer_list_->AddObserver(observer); | 164 const TabDataUseObserver* observer, |
| 165 const base::WeakPtr<TabDataUseObserver> weak_ptr_observer) { |
| 166 DCHECK(thread_checker_.CalledOnValidThread()); |
| 167 if (observers_.find(observer) != observers_.end()) { |
| 168 NOTREACHED() << " Same TabDataUseObserver can't be added twice"; |
| 169 return; |
| 170 } |
| 171 observers_.insert(ObserverMap::value_type(observer, weak_ptr_observer)); |
| 172 DCHECK_LT(0U, observers_.size()); |
| 164 } | 173 } |
| 165 | 174 |
| 166 void DataUseTabModel::RemoveObserver(TabDataUseObserver* observer) { | 175 void DataUseTabModel::RemoveObserver(const TabDataUseObserver* observer) { |
| 167 observer_list_->RemoveObserver(observer); | 176 DCHECK(thread_checker_.CalledOnValidThread()); |
| 177 if (observers_.find(observer) == observers_.end()) { |
| 178 NOTREACHED() << " TabDataUseObserver is not registered as an observer"; |
| 179 return; |
| 180 } |
| 181 observers_.erase(observer); |
| 168 } | 182 } |
| 169 | 183 |
| 170 base::TimeTicks DataUseTabModel::Now() const { | 184 base::TimeTicks DataUseTabModel::Now() const { |
| 171 return base::TimeTicks::Now(); | 185 return base::TimeTicks::Now(); |
| 172 } | 186 } |
| 173 | 187 |
| 174 void DataUseTabModel::NotifyObserversOfTrackingStarting(int32_t tab_id) { | 188 void DataUseTabModel::NotifyObserversOfTrackingStarting( |
| 175 observer_list_->Notify(FROM_HERE, &TabDataUseObserver::NotifyTrackingStarting, | 189 SessionID::id_type tab_id) { |
| 176 tab_id); | 190 DCHECK(thread_checker_.CalledOnValidThread()); |
| 191 DCHECK(ui_task_runner_); |
| 192 for (const auto& it : observers_) { |
| 193 ui_task_runner_->PostTask( |
| 194 FROM_HERE, base::Bind(&TabDataUseObserver::NotifyTrackingStarting, |
| 195 it.second, tab_id)); |
| 196 } |
| 177 } | 197 } |
| 178 | 198 |
| 179 void DataUseTabModel::NotifyObserversOfTrackingEnding(int32_t tab_id) { | 199 void DataUseTabModel::NotifyObserversOfTrackingEnding( |
| 180 observer_list_->Notify(FROM_HERE, &TabDataUseObserver::NotifyTrackingEnding, | 200 SessionID::id_type tab_id) { |
| 181 tab_id); | 201 DCHECK(thread_checker_.CalledOnValidThread()); |
| 202 DCHECK(ui_task_runner_); |
| 203 for (const auto& it : observers_) { |
| 204 ui_task_runner_->PostTask( |
| 205 FROM_HERE, base::Bind(&TabDataUseObserver::NotifyTrackingEnding, |
| 206 it.second, tab_id)); |
| 207 } |
| 182 } | 208 } |
| 183 | 209 |
| 184 void DataUseTabModel::StartTrackingDataUse(int32_t tab_id, | 210 void DataUseTabModel::StartTrackingDataUse(SessionID::id_type tab_id, |
| 185 const std::string& label) { | 211 const std::string& label) { |
| 186 // TODO(rajendrant): Explore ability to handle changes in label for current | 212 // TODO(rajendrant): Explore ability to handle changes in label for current |
| 187 // session. | 213 // session. |
| 188 bool new_tab_entry_added = false; | 214 bool new_tab_entry_added = false; |
| 189 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); | 215 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); |
| 190 if (tab_entry_iterator == active_tabs_.end()) { | 216 if (tab_entry_iterator == active_tabs_.end()) { |
| 191 auto new_entry = | 217 auto new_entry = |
| 192 active_tabs_.insert(TabEntryMap::value_type(tab_id, TabDataUseEntry())); | 218 active_tabs_.insert(TabEntryMap::value_type(tab_id, TabDataUseEntry())); |
| 193 tab_entry_iterator = new_entry.first; | 219 tab_entry_iterator = new_entry.first; |
| 194 DCHECK(tab_entry_iterator != active_tabs_.end()); | 220 DCHECK(tab_entry_iterator != active_tabs_.end()); |
| 195 DCHECK(!tab_entry_iterator->second.IsTrackingDataUse()); | 221 DCHECK(!tab_entry_iterator->second.IsTrackingDataUse()); |
| 196 new_tab_entry_added = true; | 222 new_tab_entry_added = true; |
| 197 } | 223 } |
| 198 if (tab_entry_iterator->second.StartTracking(label)) | 224 if (tab_entry_iterator->second.StartTracking(label)) |
| 199 NotifyObserversOfTrackingStarting(tab_id); | 225 NotifyObserversOfTrackingStarting(tab_id); |
| 200 | 226 |
| 201 if (new_tab_entry_added) | 227 if (new_tab_entry_added) |
| 202 CompactTabEntries(); // Keep total number of tab entries within limit. | 228 CompactTabEntries(); // Keep total number of tab entries within limit. |
| 203 } | 229 } |
| 204 | 230 |
| 205 void DataUseTabModel::EndTrackingDataUse(int32_t tab_id) { | 231 void DataUseTabModel::EndTrackingDataUse(SessionID::id_type tab_id) { |
| 206 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); | 232 TabEntryMap::iterator tab_entry_iterator = active_tabs_.find(tab_id); |
| 207 if (tab_entry_iterator != active_tabs_.end() && | 233 if (tab_entry_iterator != active_tabs_.end() && |
| 208 tab_entry_iterator->second.EndTracking()) { | 234 tab_entry_iterator->second.EndTracking()) { |
| 209 NotifyObserversOfTrackingEnding(tab_id); | 235 NotifyObserversOfTrackingEnding(tab_id); |
| 210 } | 236 } |
| 211 } | 237 } |
| 212 | 238 |
| 213 void DataUseTabModel::CompactTabEntries() { | 239 void DataUseTabModel::CompactTabEntries() { |
| 214 // Remove expired tab entries. | 240 // Remove expired tab entries. |
| 215 for (TabEntryMap::iterator tab_entry_iterator = active_tabs_.begin(); | 241 for (TabEntryMap::iterator tab_entry_iterator = active_tabs_.begin(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 kUMAUnexpiredTabEntryRemovalDurationMinutesHistogram, | 281 kUMAUnexpiredTabEntryRemovalDurationMinutesHistogram, |
| 256 Now() - oldest_tab_entry_iterator->second.GetLatestStartOrEndTime(), | 282 Now() - oldest_tab_entry_iterator->second.GetLatestStartOrEndTime(), |
| 257 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromHours(1), 50); | 283 base::TimeDelta::FromMinutes(1), base::TimeDelta::FromHours(1), 50); |
| 258 active_tabs_.erase(oldest_tab_entry_iterator); | 284 active_tabs_.erase(oldest_tab_entry_iterator); |
| 259 } | 285 } |
| 260 } | 286 } |
| 261 | 287 |
| 262 } // namespace android | 288 } // namespace android |
| 263 | 289 |
| 264 } // namespace chrome | 290 } // namespace chrome |
| OLD | NEW |