1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settingslib.net; 18 19 import android.annotation.NonNull; 20 import android.app.usage.NetworkStats; 21 import android.app.usage.NetworkStatsManager; 22 import android.content.Context; 23 import android.net.NetworkPolicy; 24 import android.net.NetworkPolicyManager; 25 import android.net.NetworkTemplate; 26 import android.text.format.DateUtils; 27 import android.util.Pair; 28 import android.util.Range; 29 30 import androidx.annotation.VisibleForTesting; 31 import androidx.loader.content.AsyncTaskLoader; 32 33 import com.android.settingslib.NetworkPolicyEditor; 34 35 import java.time.ZonedDateTime; 36 import java.util.ArrayList; 37 import java.util.Iterator; 38 39 /** 40 * Loader for network data usage history. It returns a list of usage data per billing cycle. 41 */ 42 public abstract class NetworkCycleDataLoader<D> extends AsyncTaskLoader<D> { 43 private static final String TAG = "NetworkCycleDataLoader"; 44 protected final NetworkStatsManager mNetworkStatsManager; 45 protected final NetworkTemplate mNetworkTemplate; 46 private final NetworkPolicy mPolicy; 47 private final ArrayList<Long> mCycles; 48 NetworkCycleDataLoader(Builder<?> builder)49 protected NetworkCycleDataLoader(Builder<?> builder) { 50 super(builder.mContext); 51 mNetworkTemplate = builder.mNetworkTemplate; 52 mCycles = builder.mCycles; 53 mNetworkStatsManager = (NetworkStatsManager) 54 builder.mContext.getSystemService(Context.NETWORK_STATS_SERVICE); 55 final NetworkPolicyEditor policyEditor = 56 new NetworkPolicyEditor(NetworkPolicyManager.from(builder.mContext)); 57 policyEditor.read(); 58 mPolicy = policyEditor.getPolicy(mNetworkTemplate); 59 } 60 61 @Override onStartLoading()62 protected void onStartLoading() { 63 super.onStartLoading(); 64 forceLoad(); 65 } 66 loadInBackground()67 public D loadInBackground() { 68 if (mCycles != null && mCycles.size() > 1) { 69 loadDataForSpecificCycles(); 70 } else if (mPolicy == null) { 71 loadFourWeeksData(); 72 } else { 73 loadPolicyData(); 74 } 75 return getCycleUsage(); 76 } 77 78 @VisibleForTesting loadPolicyData()79 void loadPolicyData() { 80 final Iterator<Pair<ZonedDateTime, ZonedDateTime>> iterator = 81 NetworkPolicyManager.cycleIterator(mPolicy); 82 while (iterator.hasNext()) { 83 final Pair<ZonedDateTime, ZonedDateTime> cycle = iterator.next(); 84 final long cycleStart = cycle.first.toInstant().toEpochMilli(); 85 final long cycleEnd = cycle.second.toInstant().toEpochMilli(); 86 recordUsage(cycleStart, cycleEnd); 87 } 88 } 89 90 @Override onStopLoading()91 protected void onStopLoading() { 92 super.onStopLoading(); 93 cancelLoad(); 94 } 95 96 @Override onReset()97 protected void onReset() { 98 super.onReset(); 99 cancelLoad(); 100 } 101 102 @VisibleForTesting loadFourWeeksData()103 void loadFourWeeksData() { 104 if (mNetworkTemplate == null) return; 105 final NetworkStats stats = mNetworkStatsManager.queryDetailsForDevice( 106 mNetworkTemplate, Long.MIN_VALUE, Long.MAX_VALUE); 107 try { 108 final Range<Long> historyTimeRange = getTimeRangeOf(stats); 109 110 long cycleEnd = historyTimeRange.getUpper(); 111 while (cycleEnd > historyTimeRange.getLower()) { 112 final long cycleStart = cycleEnd - (DateUtils.WEEK_IN_MILLIS * 4); 113 recordUsage(cycleStart, cycleEnd); 114 cycleEnd = cycleStart; 115 } 116 } catch (IllegalArgumentException e) { 117 // Empty history, ignore. 118 } 119 } 120 121 @VisibleForTesting loadDataForSpecificCycles()122 void loadDataForSpecificCycles() { 123 long cycleEnd = mCycles.get(0); 124 final int lastCycleIndex = mCycles.size() - 1; 125 for (int i = 1; i <= lastCycleIndex; i++) { 126 final long cycleStart = mCycles.get(i); 127 recordUsage(cycleStart, cycleEnd); 128 cycleEnd = cycleStart; 129 } 130 } 131 132 @VisibleForTesting recordUsage(long start, long end)133 abstract void recordUsage(long start, long end); 134 getCycleUsage()135 abstract D getCycleUsage(); 136 builder(Context context)137 public static Builder<?> builder(Context context) { 138 return new Builder<NetworkCycleDataLoader>(context) { 139 @Override 140 public NetworkCycleDataLoader build() { 141 return null; 142 } 143 }; 144 } 145 146 protected long getTotalUsage(NetworkStats stats) { 147 long bytes = 0L; 148 if (stats != null) { 149 final NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 150 while (stats.hasNextBucket() && stats.getNextBucket(bucket)) { 151 bytes += bucket.getRxBytes() + bucket.getTxBytes(); 152 } 153 stats.close(); 154 } 155 return bytes; 156 } 157 158 @NonNull 159 @VisibleForTesting 160 Range getTimeRangeOf(@NonNull NetworkStats stats) { 161 long start = Long.MAX_VALUE; 162 long end = Long.MIN_VALUE; 163 while (hasNextBucket(stats)) { 164 final NetworkStats.Bucket bucket = getNextBucket(stats); 165 start = Math.min(start, bucket.getStartTimeStamp()); 166 end = Math.max(end, bucket.getEndTimeStamp()); 167 } 168 return new Range(start, end); 169 } 170 171 @VisibleForTesting 172 boolean hasNextBucket(@NonNull NetworkStats stats) { 173 return stats.hasNextBucket(); 174 } 175 176 @NonNull 177 @VisibleForTesting 178 NetworkStats.Bucket getNextBucket(@NonNull NetworkStats stats) { 179 NetworkStats.Bucket bucket = new NetworkStats.Bucket(); 180 stats.getNextBucket(bucket); 181 return bucket; 182 } 183 184 @VisibleForTesting(otherwise = VisibleForTesting.NONE) 185 public ArrayList<Long> getCycles() { 186 return mCycles; 187 } 188 189 public static abstract class Builder<T extends NetworkCycleDataLoader> { 190 private final Context mContext; 191 private NetworkTemplate mNetworkTemplate; 192 private ArrayList<Long> mCycles; 193 194 public Builder (Context context) { 195 mContext = context; 196 } 197 198 public Builder<T> setNetworkTemplate(NetworkTemplate template) { 199 mNetworkTemplate = template; 200 return this; 201 } 202 203 /** 204 * Sets the network cycles to be used to query the usage data. 205 * @param cycles the time slots for the network cycle to be used to query the network usage. 206 * @return the builder 207 */ 208 public Builder<T> setCycles(ArrayList<Long> cycles) { 209 mCycles = cycles; 210 return this; 211 } 212 213 public abstract T build(); 214 } 215 216 } 217