| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.android.internal.util; |
| |
| import android.os.SystemClock; |
| import android.util.SparseBooleanArray; |
| import android.util.SparseLongArray; |
| |
| import java.io.PrintWriter; |
| |
| public class ProviderAccessStats { |
| private final Object mLock = new Object(); |
| |
| private final long mStartUptime = SystemClock.uptimeMillis(); |
| |
| private final SparseBooleanArray mAllCallingUids = new SparseBooleanArray(); |
| private final SparseLongArray mQueryStats = new SparseLongArray(16); |
| private final SparseLongArray mBatchStats = new SparseLongArray(0); |
| private final SparseLongArray mInsertStats = new SparseLongArray(0); |
| private final SparseLongArray mUpdateStats = new SparseLongArray(0); |
| private final SparseLongArray mDeleteStats = new SparseLongArray(0); |
| private final SparseLongArray mInsertInBatchStats = new SparseLongArray(0); |
| private final SparseLongArray mUpdateInBatchStats = new SparseLongArray(0); |
| private final SparseLongArray mDeleteInBatchStats = new SparseLongArray(0); |
| |
| private final SparseLongArray mOperationDurationMillis = new SparseLongArray(16); |
| |
| private static class PerThreadData { |
| public int nestCount; |
| public long startUptimeMillis; |
| } |
| |
| private final ThreadLocal<PerThreadData> mThreadLocal = |
| ThreadLocal.withInitial(() -> new PerThreadData()); |
| |
| private void incrementStats(int callingUid, SparseLongArray stats) { |
| synchronized (mLock) { |
| stats.put(callingUid, stats.get(callingUid) + 1); |
| mAllCallingUids.put(callingUid, true); |
| } |
| |
| final PerThreadData data = mThreadLocal.get(); |
| data.nestCount++; |
| if (data.nestCount == 1) { |
| data.startUptimeMillis = SystemClock.uptimeMillis(); |
| } |
| } |
| |
| private void incrementStats(int callingUid, boolean inBatch, |
| SparseLongArray statsNonBatch, SparseLongArray statsInBatch) { |
| incrementStats(callingUid, inBatch ? statsInBatch : statsNonBatch); |
| } |
| |
| public final void incrementInsertStats(int callingUid, boolean inBatch) { |
| incrementStats(callingUid, inBatch, mInsertStats, mInsertInBatchStats); |
| } |
| |
| public final void incrementUpdateStats(int callingUid, boolean inBatch) { |
| incrementStats(callingUid, inBatch, mUpdateStats, mUpdateInBatchStats); |
| } |
| |
| public final void incrementDeleteStats(int callingUid, boolean inBatch) { |
| incrementStats(callingUid, inBatch, mDeleteStats, mDeleteInBatchStats); |
| } |
| |
| public final void incrementQueryStats(int callingUid) { |
| incrementStats(callingUid, mQueryStats); |
| } |
| |
| public final void incrementBatchStats(int callingUid) { |
| incrementStats(callingUid, mBatchStats); |
| } |
| |
| public void finishOperation(int callingUid) { |
| final PerThreadData data = mThreadLocal.get(); |
| data.nestCount--; |
| if (data.nestCount == 0) { |
| // Because we only have millisecond granularity, let's always attribute at least 1ms |
| // for each operation. |
| final long duration = Math.max(1, SystemClock.uptimeMillis() - data.startUptimeMillis); |
| |
| synchronized (mLock) { |
| mOperationDurationMillis.put(callingUid, |
| mOperationDurationMillis.get(callingUid) + duration); |
| } |
| } |
| } |
| |
| public void dump(PrintWriter pw, String prefix) { |
| synchronized (mLock) { |
| pw.print(" Process uptime: "); |
| pw.print((SystemClock.uptimeMillis() - mStartUptime) / (60 * 1000)); |
| pw.println(" minutes"); |
| pw.println(); |
| |
| pw.print(prefix); |
| pw.println("Client activities:"); |
| pw.print(prefix); |
| pw.println(" UID Query Insert Update Delete Batch Insert Update Delete" |
| + " Sec"); |
| for (int i = 0; i < mAllCallingUids.size(); i++) { |
| final int uid = mAllCallingUids.keyAt(i); |
| pw.print(prefix); |
| pw.println(String.format( |
| " %-9d %6d %6d %6d %6d %6d %6d %6d %6d %12.3f", |
| uid, |
| mQueryStats.get(uid), |
| mInsertStats.get(uid), |
| mUpdateStats.get(uid), |
| mDeleteStats.get(uid), |
| mBatchStats.get(uid), |
| mInsertInBatchStats.get(uid), |
| mUpdateInBatchStats.get(uid), |
| mDeleteInBatchStats.get(uid), |
| (mOperationDurationMillis.get(uid) / 1000.0) |
| )); |
| } |
| pw.println(); |
| } |
| } |
| } |