OLD | NEW |
1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium OS 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 "src/data_plan.h" | 5 #include "src/data_plan.h" |
6 | 6 |
7 #include <time.h> | 7 #include <time.h> |
8 | 8 |
9 #include <glog/logging.h> | 9 #include <glog/logging.h> |
10 | 10 |
| 11 #include "src/device.h" |
11 #include "src/policy.h" | 12 #include "src/policy.h" |
| 13 #include "src/service_manager.h" |
12 | 14 |
13 namespace cashew { | 15 namespace cashew { |
14 | 16 |
15 // libcros CellularDataPlan property names | 17 // libcros CellularDataPlan property names |
16 // (what we send to libcros) | 18 // (what we send to libcros) |
17 static const char *kCellularDataPlanName = "CellularPlanName"; | 19 static const char *kCellularDataPlanName = "CellularPlanName"; |
18 static const char *kCellularDataPlanType = "CellularPlanType"; | 20 static const char *kCellularDataPlanType = "CellularPlanType"; |
19 static const char *kCellularDataPlanUpdateTime = "CellularPlanUpdateTime"; | 21 static const char *kCellularDataPlanUpdateTime = "CellularPlanUpdateTime"; |
20 static const char *kCellularDataPlanStartTime = "CellularPlanStart"; | 22 static const char *kCellularDataPlanStartTime = "CellularPlanStart"; |
21 static const char *kCellularDataPlanEndTime = "CellularPlanEnd"; | 23 static const char *kCellularDataPlanEndTime = "CellularPlanEnd"; |
(...skipping 15 matching lines...) Expand all Loading... |
37 static const char *kCrosUsageDataPlanEndTimeProperty = "expirationTime"; | 39 static const char *kCrosUsageDataPlanEndTimeProperty = "expirationTime"; |
38 static const char *kCrosUsageDataPlanStartTimeProperty = "startTime"; | 40 static const char *kCrosUsageDataPlanStartTimeProperty = "startTime"; |
39 | 41 |
40 // Chromium OS Usage API Data Plan type values | 42 // Chromium OS Usage API Data Plan type values |
41 static const char *kCrosUsageDataPlanTypeUnlimited = "UNLIMITED"; | 43 static const char *kCrosUsageDataPlanTypeUnlimited = "UNLIMITED"; |
42 static const char *kCrosUsageDataPlanTypeMeteredFree = "METERED_FREE"; | 44 static const char *kCrosUsageDataPlanTypeMeteredFree = "METERED_FREE"; |
43 static const char *kCrosUsageDataPlanTypeMeteredPaid = "METERED_PAID"; | 45 static const char *kCrosUsageDataPlanTypeMeteredPaid = "METERED_PAID"; |
44 | 46 |
45 DataPlan::DataPlan(const std::string& name, DataPlan::Type type, | 47 DataPlan::DataPlan(const std::string& name, DataPlan::Type type, |
46 base::Time update_time, base::Time start_time, | 48 base::Time update_time, base::Time start_time, |
47 base::Time end_time, Bytes data_bytes_max, | 49 base::Time end_time, ByteCount data_bytes_max, |
48 Bytes data_bytes_used) | 50 ByteCount data_bytes_used) |
49 : name_(name), type_(type), update_time_(update_time), | 51 : name_(name), type_(type), update_time_(update_time), |
50 start_time_(start_time), end_time_(end_time), | 52 start_time_(start_time), end_time_(end_time), |
51 data_bytes_max_(data_bytes_max), data_bytes_used_(data_bytes_used), | 53 data_bytes_max_(data_bytes_max), data_bytes_used_(data_bytes_used), |
52 local_bytes_used_(0), total_bytes_used_(data_bytes_used) { | 54 local_bytes_used_(0), total_bytes_used_(data_bytes_used) { |
53 CHECK_GE(data_bytes_max_, 0); | 55 CHECK_GE(data_bytes_max_, 0); |
54 CHECK_GE(data_bytes_used_, 0); | 56 CHECK_GE(data_bytes_used_, 0); |
55 } | 57 } |
56 | 58 |
57 DataPlan::~DataPlan() { | 59 DataPlan::~DataPlan() { |
58 } | 60 } |
(...skipping 11 matching lines...) Expand all Loading... |
70 } | 72 } |
71 | 73 |
72 base::Time DataPlan::GetStartTime() const { | 74 base::Time DataPlan::GetStartTime() const { |
73 return start_time_; | 75 return start_time_; |
74 } | 76 } |
75 | 77 |
76 base::Time DataPlan::GetEndTime() const { | 78 base::Time DataPlan::GetEndTime() const { |
77 return end_time_; | 79 return end_time_; |
78 } | 80 } |
79 | 81 |
80 Bytes DataPlan::GetDataBytesMax() const { | 82 ByteCount DataPlan::GetDataBytesMax() const { |
81 return data_bytes_max_; | 83 return data_bytes_max_; |
82 } | 84 } |
83 | 85 |
84 Bytes DataPlan::GetDataBytesUsed() const { | 86 ByteCount DataPlan::GetDataBytesUsed() const { |
85 return data_bytes_used_; | 87 return data_bytes_used_; |
86 } | 88 } |
87 | 89 |
88 Bytes DataPlan::GetLocalBytesUsed() const { | 90 ByteCount DataPlan::GetLocalBytesUsed() const { |
89 return local_bytes_used_; | 91 return local_bytes_used_; |
90 } | 92 } |
91 | 93 |
92 Bytes DataPlan::GetTotalBytesUsed() const { | 94 ByteCount DataPlan::GetTotalBytesUsed() const { |
93 return total_bytes_used_; | 95 return total_bytes_used_; |
94 } | 96 } |
95 | 97 |
96 void DataPlan::SetLocalBytesUsed(Bytes local_bytes_used) { | 98 // TODO(vlaviano): ensure that this method stops the plan's expiration timer |
| 99 // (when it is implemented in a future CL) if the plan is fully consumed |
| 100 void DataPlan::SetLocalBytesUsed(ByteCount local_bytes_used) { |
97 CHECK_GE(local_bytes_used, 0); | 101 CHECK_GE(local_bytes_used, 0); |
98 local_bytes_used_ = local_bytes_used; | 102 local_bytes_used_ = local_bytes_used; |
99 total_bytes_used_ = data_bytes_used_ + local_bytes_used_; | 103 total_bytes_used_ = data_bytes_used_ + local_bytes_used_; |
100 if (total_bytes_used_ < 0) { | 104 if (total_bytes_used_ < 0) { |
101 LOG(WARNING) << "SetLocalBytesUsed: overflow detected"; | 105 LOG(WARNING) << "SetLocalBytesUsed: overflow detected"; |
102 total_bytes_used_ = kint64max; | 106 total_bytes_used_ = kint64max; |
103 } | 107 } |
104 } | 108 } |
105 | 109 |
106 bool DataPlan::IsActive() const { | 110 bool DataPlan::IsActive() const { |
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 for (it = data_plans.begin(); it != data_plans.end(); ++it) { | 313 for (it = data_plans.begin(); it != data_plans.end(); ++it) { |
310 DataPlan *plan = *it; | 314 DataPlan *plan = *it; |
311 DCHECK(plan != NULL); | 315 DCHECK(plan != NULL); |
312 if (plan->IsActive()) { | 316 if (plan->IsActive()) { |
313 return plan; | 317 return plan; |
314 } | 318 } |
315 } | 319 } |
316 return NULL; | 320 return NULL; |
317 } | 321 } |
318 | 322 |
| 323 // static |
| 324 bool DataPlan::OnByteCounterUpdate(DataPlanList *data_plans, Service *service, |
| 325 ServiceManager *service_manager, |
| 326 Device *device, uint64 rx_bytes, |
| 327 uint64 tx_bytes) { |
| 328 DCHECK(data_plans != NULL); |
| 329 DCHECK(service != NULL); |
| 330 DCHECK(service_manager != NULL); |
| 331 DCHECK(device != NULL); |
| 332 DCHECK(device->ByteCounterRunning()); |
| 333 DLOG(INFO) << "OnByteCounterUpdate: rx_bytes = " << rx_bytes |
| 334 << ", tx_bytes = " << tx_bytes; |
| 335 DataPlan *active_plan = DataPlan::GetActivePlan(*data_plans); |
| 336 if (active_plan == NULL) { |
| 337 DLOG(WARNING) << "OnByteCounterUpdate: no active plan"; |
| 338 device->StopByteCounter(); |
| 339 return false; |
| 340 } |
| 341 ByteCount local_bytes_used = rx_bytes + tx_bytes; |
| 342 DLOG(INFO) << "OnByteCounterUpdate: local_bytes_used = " << local_bytes_used; |
| 343 // try to detect two error conditions: |
| 344 // (1) overflow of the unsigned addition above prior to the assignment |
| 345 // (2) no overflow, but result has high order bit set and so is interpreted as |
| 346 // a negative number when assigned to |local_bytes_used| |
| 347 if (local_bytes_used < 0 || |
| 348 static_cast<uint64>(local_bytes_used) < rx_bytes || |
| 349 static_cast<uint64>(local_bytes_used) < tx_bytes) { |
| 350 LOG(WARNING) << "OnByteCounterUpdate: overflow detected"; |
| 351 return false; |
| 352 } |
| 353 // compute delta since last sample |
| 354 // this delta represents the data usage that we need to assign to active plans |
| 355 // this computation relies on the local counter being based on the currently |
| 356 // active plan |
| 357 // TODO(vlaviano): Currently, this is not always true. It's possible for the |
| 358 // local byte counter to be associated with a plan that was active at the |
| 359 // beginning of the sample interval but has now expired. A future CL will |
| 360 // add expiration timers to plan objects to handle this case. |
| 361 ByteCount previous_local_bytes_used = active_plan->GetLocalBytesUsed(); |
| 362 DLOG(INFO) << "OnByteCounterUpdate: previous_local_bytes_used = " |
| 363 << previous_local_bytes_used; |
| 364 DCHECK_LE(previous_local_bytes_used, local_bytes_used); |
| 365 ByteCount used_bytes_to_assign = local_bytes_used - previous_local_bytes_used; |
| 366 DLOG(INFO) << "OnByteCounterUpdate: used_bytes_to_assign = " |
| 367 << used_bytes_to_assign; |
| 368 // iterate through active plans, assigning as much data as possible to each |
| 369 // plan and expiring it if its data quota is fully consumed |
| 370 ByteCount assigned_bytes = 0; |
| 371 bool any_plan_updated = false; |
| 372 while (used_bytes_to_assign > 0 && active_plan != NULL) { |
| 373 ByteCount active_plan_data_remaining = 0; // relevant for metered plans |
| 374 if (active_plan->GetType() != DataPlan::kTypeUnlimited) { |
| 375 active_plan_data_remaining = active_plan->GetDataBytesMax() - |
| 376 active_plan->GetTotalBytesUsed(); |
| 377 DCHECK_GE(active_plan_data_remaining, 0); |
| 378 } |
| 379 if (active_plan->GetType() == DataPlan::kTypeUnlimited || |
| 380 used_bytes_to_assign < active_plan_data_remaining) { |
| 381 // can assign all data from this sample and plan not fully consumed |
| 382 assigned_bytes = used_bytes_to_assign; |
| 383 used_bytes_to_assign = 0; |
| 384 } else { |
| 385 // plan fully consumed, and there might be an overage remaining to be |
| 386 // assigned to the next active plan |
| 387 assigned_bytes = active_plan_data_remaining; |
| 388 used_bytes_to_assign -= assigned_bytes; |
| 389 } |
| 390 DCHECK_GE(assigned_bytes, 0); |
| 391 active_plan->SetLocalBytesUsed(previous_local_bytes_used + assigned_bytes); |
| 392 any_plan_updated = true; |
| 393 DLOG(INFO) << "OnByteCounterUpdate: " << active_plan->GetName() |
| 394 << ": updated plan state: data bytes used = " |
| 395 << active_plan->GetDataBytesUsed() << ", local bytes used = " |
| 396 << active_plan->GetLocalBytesUsed() << ", total bytes used = " |
| 397 << active_plan->GetTotalBytesUsed(); |
| 398 |
| 399 if (!active_plan->IsActive()) { |
| 400 // notify service manager that plan has become inactive |
| 401 service_manager->OnDataPlanInactive(*service, *active_plan); |
| 402 |
| 403 // we've consumed a plan, so reset byte counter to only reflect overage |
| 404 // TODO(vlaviano): byte counter api shouldn't expose rx/tx split. |
| 405 device->ResetByteCounter(used_bytes_to_assign, 0); |
| 406 active_plan = DataPlan::GetActivePlan(*data_plans); |
| 407 } |
| 408 } |
| 409 |
| 410 // if we have no more active plans, stop our local counter |
| 411 if (active_plan == NULL) { |
| 412 device->StopByteCounter(); |
| 413 // warn if we've measured usage beyond what should have been available |
| 414 if (used_bytes_to_assign > 0) { |
| 415 DLOG(WARNING) << "OnByteCounterUpdate: used_bytes_to_assign = " |
| 416 << used_bytes_to_assign << ", but no active plan"; |
| 417 } |
| 418 } |
| 419 return any_plan_updated; |
| 420 } |
| 421 |
319 // private methods | 422 // private methods |
320 | 423 |
321 const char* DataPlan::TypeToLibcrosString(DataPlan::Type type) const { | 424 const char* DataPlan::TypeToLibcrosString(DataPlan::Type type) const { |
322 switch (type) { | 425 switch (type) { |
323 case kTypeUnlimited: | 426 case kTypeUnlimited: |
324 return kCellularDataPlanTypeUnlimited; | 427 return kCellularDataPlanTypeUnlimited; |
325 case kTypeMeteredFree: | 428 case kTypeMeteredFree: |
326 return kCellularDataPlanTypeMeteredFree; | 429 return kCellularDataPlanTypeMeteredFree; |
327 case kTypeMeteredPaid: | 430 case kTypeMeteredPaid: |
328 return kCellularDataPlanTypeMeteredPaid; | 431 return kCellularDataPlanTypeMeteredPaid; |
(...skipping 28 matching lines...) Expand all Loading... |
357 *out_value = generic_int_out; | 460 *out_value = generic_int_out; |
358 return true; | 461 return true; |
359 } | 462 } |
360 if (dict.GetInteger64(key, out_value)) { | 463 if (dict.GetInteger64(key, out_value)) { |
361 return true; | 464 return true; |
362 } | 465 } |
363 return false; | 466 return false; |
364 } | 467 } |
365 | 468 |
366 } // namespace cashew | 469 } // namespace cashew |
OLD | NEW |