OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / telephony / java / android / telephony / TelephonyHistogram.java
1 /*
2  * Copyright (C) 2016 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 package android.telephony;
17
18 import android.annotation.SystemApi;
19 import android.os.Parcel;
20 import android.os.Parcelable;
21
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
25
26 /**
27  * Parcelable class to store Telephony histogram.
28  * @hide
29  */
30 @SystemApi
31 public final class TelephonyHistogram implements Parcelable {
32     // Type of Telephony histogram Eg: RIL histogram will have all timing data associated with
33     // RIL calls. Similarly we can have any other Telephony histogram.
34     private final int mCategory;
35
36     // Unique Id identifying a sample within particular category of histogram
37     private final int mId;
38
39     // Min time taken in ms
40     private int mMinTimeMs;
41
42     // Max time taken in ms
43     private int mMaxTimeMs;
44
45     // Average time taken in ms
46     private int mAverageTimeMs;
47
48     // Total count of samples
49     private int mSampleCount;
50
51     // Array storing time taken for first #RANGE_CALCULATION_COUNT samples of histogram.
52     private int[] mInitialTimings;
53
54     // Total number of time ranges expected (must be greater than 1)
55     private final int mBucketCount;
56
57     // Array storing endpoints of range buckets. Calculated based on values of minTime & maxTime
58     // after totalTimeCount is #RANGE_CALCULATION_COUNT.
59     private final int[] mBucketEndPoints;
60
61     // Array storing counts for each time range starting from smallest value range
62     private final int[] mBucketCounters;
63
64     /**
65      * Constant for Telephony category
66      */
67     public static final int TELEPHONY_CATEGORY_RIL = 1;
68
69     // Count of Histogram samples after which time buckets are created.
70     private static final int RANGE_CALCULATION_COUNT = 10;
71
72
73     // Constant used to indicate #initialTimings is null while parceling
74     private static final int ABSENT = 0;
75
76     // Constant used to indicate #initialTimings is not null while parceling
77     private static final int PRESENT = 1;
78
79     // Throws exception if #totalBuckets is not greater than one.
80     public TelephonyHistogram (int category, int id, int bucketCount) {
81         if (bucketCount <= 1) {
82             throw new IllegalArgumentException("Invalid number of buckets");
83         }
84         mCategory = category;
85         mId = id;
86         mMinTimeMs = Integer.MAX_VALUE;
87         mMaxTimeMs = 0;
88         mAverageTimeMs = 0;
89         mSampleCount = 0;
90         mInitialTimings = new int[RANGE_CALCULATION_COUNT];
91         mBucketCount = bucketCount;
92         mBucketEndPoints = new int[bucketCount - 1];
93         mBucketCounters = new int[bucketCount];
94     }
95
96     public TelephonyHistogram(TelephonyHistogram th) {
97         mCategory = th.getCategory();
98         mId = th.getId();
99         mMinTimeMs = th.getMinTime();
100         mMaxTimeMs = th.getMaxTime();
101         mAverageTimeMs = th.getAverageTime();
102         mSampleCount = th.getSampleCount();
103         mInitialTimings = th.getInitialTimings();
104         mBucketCount = th.getBucketCount();
105         mBucketEndPoints = th.getBucketEndPoints();
106         mBucketCounters = th.getBucketCounters();
107     }
108
109     public int getCategory() {
110         return mCategory;
111     }
112
113     public int getId() {
114         return mId;
115     }
116
117     public int getMinTime() {
118         return mMinTimeMs;
119     }
120
121     public int getMaxTime() {
122         return mMaxTimeMs;
123     }
124
125     public int getAverageTime() {
126         return mAverageTimeMs;
127     }
128
129     public int getSampleCount () {
130         return mSampleCount;
131     }
132
133     private int[] getInitialTimings() {
134         return mInitialTimings;
135     }
136
137     public int getBucketCount() {
138         return mBucketCount;
139     }
140
141     public int[] getBucketEndPoints() {
142         if (mSampleCount > 1 && mSampleCount < 10) {
143             int[] tempEndPoints = new int[mBucketCount - 1];
144             calculateBucketEndPoints(tempEndPoints);
145             return tempEndPoints;
146         } else {
147             return getDeepCopyOfArray(mBucketEndPoints);
148         }
149     }
150
151     public int[] getBucketCounters() {
152         if (mSampleCount > 1 && mSampleCount < 10) {
153             int[] tempEndPoints = new int[mBucketCount - 1];
154             int[] tempBucketCounters = new int[mBucketCount];
155             calculateBucketEndPoints(tempEndPoints);
156             for (int j = 0; j < mSampleCount; j++) {
157                 addToBucketCounter(tempEndPoints, tempBucketCounters, mInitialTimings[j]);
158             }
159             return tempBucketCounters;
160         } else {
161             return getDeepCopyOfArray(mBucketCounters);
162         }
163     }
164
165     private int[] getDeepCopyOfArray(int[] array) {
166         int[] clone = new int[array.length];
167         System.arraycopy(array, 0, clone, 0, array.length);
168         return clone;
169     }
170
171     private void addToBucketCounter(int[] bucketEndPoints, int[] bucketCounters, int time) {
172         int i;
173         for (i = 0; i < bucketEndPoints.length; i++) {
174             if (time <= bucketEndPoints[i]) {
175                 bucketCounters[i]++;
176                 return;
177             }
178         }
179         bucketCounters[i]++;
180     }
181
182     private void calculateBucketEndPoints(int[] bucketEndPoints) {
183         for (int i = 1; i < mBucketCount; i++) {
184             int endPt = mMinTimeMs + (i * (mMaxTimeMs - mMinTimeMs)) / mBucketCount;
185             bucketEndPoints[i - 1] = endPt;
186         }
187     }
188
189     // Add new value of time taken
190     // This function updates minTime, maxTime, averageTime & totalTimeCount every time it is
191     // called. initialTimings[] is updated if totalTimeCount <= #RANGE_CALCULATION_COUNT. When
192     // totalTimeCount = RANGE_CALCULATION_COUNT, based on the min, max time & the number of buckets
193     // expected, bucketEndPoints[] would be calculated. Then bucketCounters[] would be filled up
194     // using values stored in initialTimings[]. Thereafter bucketCounters[] will always be updated.
195     public void addTimeTaken(int time) {
196         // Initialize all fields if its first entry or if integer overflow is going to occur while
197         // trying to calculate averageTime
198         if (mSampleCount == 0 || (mSampleCount == Integer.MAX_VALUE)) {
199             if (mSampleCount == 0) {
200                 mMinTimeMs = time;
201                 mMaxTimeMs = time;
202                 mAverageTimeMs = time;
203             } else {
204                 mInitialTimings = new int[RANGE_CALCULATION_COUNT];
205             }
206             mSampleCount = 1;
207             Arrays.fill(mInitialTimings, 0);
208             mInitialTimings[0] = time;
209             Arrays.fill(mBucketEndPoints, 0);
210             Arrays.fill(mBucketCounters, 0);
211         } else {
212             if (time < mMinTimeMs) {
213                 mMinTimeMs = time;
214             }
215             if (time > mMaxTimeMs) {
216                 mMaxTimeMs = time;
217             }
218             long totalTime = ((long)mAverageTimeMs) * mSampleCount + time;
219             mAverageTimeMs = (int)(totalTime/++mSampleCount);
220
221             if (mSampleCount < RANGE_CALCULATION_COUNT) {
222                 mInitialTimings[mSampleCount - 1] = time;
223             } else if (mSampleCount == RANGE_CALCULATION_COUNT) {
224                 mInitialTimings[mSampleCount - 1] = time;
225
226                 // Calculate bucket endpoints based on bucketCount expected
227                 calculateBucketEndPoints(mBucketEndPoints);
228
229                 // Use values stored in initialTimings[] to update bucketCounters
230                 for (int j = 0; j < RANGE_CALCULATION_COUNT; j++) {
231                     addToBucketCounter(mBucketEndPoints, mBucketCounters, mInitialTimings[j]);
232                 }
233                 mInitialTimings = null;
234             } else {
235                 addToBucketCounter(mBucketEndPoints, mBucketCounters, time);
236             }
237
238         }
239     }
240
241     public String toString() {
242         String basic = " Histogram id = " + mId + " Time(ms): min = " + mMinTimeMs + " max = "
243                 + mMaxTimeMs + " avg = " + mAverageTimeMs + " Count = " + mSampleCount;
244         if (mSampleCount < RANGE_CALCULATION_COUNT) {
245             return basic;
246         } else {
247             StringBuffer intervals = new StringBuffer(" Interval Endpoints:");
248             for (int i = 0; i < mBucketEndPoints.length; i++) {
249                 intervals.append(" " + mBucketEndPoints[i]);
250             }
251             intervals.append(" Interval counters:");
252             for (int i = 0; i < mBucketCounters.length; i++) {
253                 intervals.append(" " + mBucketCounters[i]);
254             }
255             return basic + intervals;
256         }
257     }
258
259     public static final Parcelable.Creator<TelephonyHistogram> CREATOR =
260             new Parcelable.Creator<TelephonyHistogram> () {
261
262                 @Override
263                 public TelephonyHistogram createFromParcel(Parcel in) {
264                     return new TelephonyHistogram(in);
265                 }
266
267                 @Override
268                 public TelephonyHistogram[] newArray(int size) {
269                     return new TelephonyHistogram[size];
270                 }
271             };
272
273     public TelephonyHistogram(Parcel in) {
274         mCategory = in.readInt();
275         mId = in.readInt();
276         mMinTimeMs = in.readInt();
277         mMaxTimeMs = in.readInt();
278         mAverageTimeMs = in.readInt();
279         mSampleCount = in.readInt();
280         if (in.readInt() == PRESENT) {
281             mInitialTimings = new int[RANGE_CALCULATION_COUNT];
282             in.readIntArray(mInitialTimings);
283         }
284         mBucketCount = in.readInt();
285         mBucketEndPoints = new int[mBucketCount - 1];
286         in.readIntArray(mBucketEndPoints);
287         mBucketCounters = new int[mBucketCount];
288         in.readIntArray(mBucketCounters);
289     }
290
291     public void writeToParcel(Parcel out, int flags) {
292         out.writeInt(mCategory);
293         out.writeInt(mId);
294         out.writeInt(mMinTimeMs);
295         out.writeInt(mMaxTimeMs);
296         out.writeInt(mAverageTimeMs);
297         out.writeInt(mSampleCount);
298         if (mInitialTimings == null) {
299             out.writeInt(ABSENT);
300         } else {
301             out.writeInt(PRESENT);
302             out.writeIntArray(mInitialTimings);
303         }
304         out.writeInt(mBucketCount);
305         out.writeIntArray(mBucketEndPoints);
306         out.writeIntArray(mBucketCounters);
307     }
308
309     @Override
310     public int describeContents() {
311         return 0;
312     }
313 }