summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2015-03-18 15:24:33 -0700
committerJohn Reck <jreck@google.com>2015-03-27 11:50:56 -0700
commitedc524c90506d80e0fc5fb67e8de7b8f3ef53439 (patch)
tree098c18daa80655fe0fa3faab7c39332685c163ef /services
parent1cef4196886b0cc1238111d396c1e3665a5fd2ae (diff)
downloadframeworks_base-edc524c90506d80e0fc5fb67e8de7b8f3ef53439.zip
frameworks_base-edc524c90506d80e0fc5fb67e8de7b8f3ef53439.tar.gz
frameworks_base-edc524c90506d80e0fc5fb67e8de7b8f3ef53439.tar.bz2
Add GraphicsStatsService
More S's for More Speed Split JankTracker's backing data from the class to allow for data relocation to/from ashmem regions Pack the jank tracking data to fit in 256 bytes Change-Id: Ife86a64b71a328fbd0c8075fe6a0404e081f725b
Diffstat (limited to 'services')
-rw-r--r--services/core/java/com/android/server/GraphicsStatsService.java256
-rw-r--r--services/java/com/android/server/SystemServer.java5
2 files changed, 261 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/services/core/java/com/android/server/GraphicsStatsService.java
new file mode 100644
index 0000000..c79fdfc
--- /dev/null
+++ b/services/core/java/com/android/server/GraphicsStatsService.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2015 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.server;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.MemoryFile;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IGraphicsStats;
+import android.view.ThreadedRenderer;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * This service's job is to collect aggregate rendering profile data. It
+ * does this by allowing rendering processes to request an ashmem buffer
+ * to place their stats into. This buffer will be pre-initialized with historical
+ * data for that process if it exists (if the userId & packageName match a buffer
+ * in the historical log)
+ *
+ * This service does not itself attempt to understand the data in the buffer,
+ * its primary job is merely to manage distributing these buffers. However,
+ * it is assumed that this buffer is for ThreadedRenderer and delegates
+ * directly to ThreadedRenderer for dumping buffers.
+ *
+ * MEMORY USAGE:
+ *
+ * This class consumes UP TO:
+ * 1) [active rendering processes] * (ASHMEM_SIZE * 2)
+ * 2) ASHMEM_SIZE (for scratch space used during dumping)
+ * 3) ASHMEM_SIZE * HISTORY_SIZE
+ *
+ * Currently ASHMEM_SIZE is 256 bytes and HISTORY_SIZE is 10. Assuming
+ * the system then also has 10 active rendering processes in the worst case
+ * this would end up using under 10KiB (8KiB for the buffers, plus some overhead
+ * for userId, pid, package name, and a couple other objects)
+ *
+ * @hide */
+public class GraphicsStatsService extends IGraphicsStats.Stub {
+ public static final String GRAPHICS_STATS_SERVICE = "graphicsstats";
+
+ private static final String TAG = "GraphicsStatsService";
+ private static final int ASHMEM_SIZE = 256;
+ private static final int HISTORY_SIZE = 10;
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private ArrayList<ActiveBuffer> mActive = new ArrayList<>();
+ private HistoricalData[] mHistoricalLog = new HistoricalData[HISTORY_SIZE];
+ private int mNextHistoricalSlot = 0;
+ private byte[] mTempBuffer = new byte[ASHMEM_SIZE];
+
+ public GraphicsStatsService(Context context) {
+ mContext = context;
+ }
+
+ private boolean isValid(int uid, String packageName) {
+ try {
+ PackageInfo info = mContext.getPackageManager().getPackageInfo(packageName, 0);
+ return info.applicationInfo.uid == uid;
+ } catch (NameNotFoundException e) {
+ }
+ return false;
+ }
+
+ @Override
+ public ParcelFileDescriptor requestBufferForProcess(String packageName, IBinder token)
+ throws RemoteException {
+ int uid = Binder.getCallingUid();
+ int pid = Binder.getCallingPid();
+ ParcelFileDescriptor pfd = null;
+ long callingIdentity = Binder.clearCallingIdentity();
+ try {
+ if (!isValid(uid, packageName)) {
+ throw new RemoteException("Invalid package name");
+ }
+ synchronized (mLock) {
+ pfd = requestBufferForProcessLocked(token, uid, pid, packageName);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(callingIdentity);
+ }
+ return pfd;
+ }
+
+ private ParcelFileDescriptor getPfd(MemoryFile file) {
+ try {
+ return new ParcelFileDescriptor(file.getFileDescriptor());
+ } catch (IOException ex) {
+ throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ }
+ }
+
+ private ParcelFileDescriptor requestBufferForProcessLocked(IBinder token,
+ int uid, int pid, String packageName) throws RemoteException {
+ ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName);
+ return getPfd(buffer.mProcessBuffer);
+ }
+
+ private void processDied(ActiveBuffer buffer) {
+ synchronized (mLock) {
+ mActive.remove(buffer);
+ Log.d("GraphicsStats", "Buffer count: " + mActive.size());
+ }
+ HistoricalData data = buffer.mPreviousData;
+ buffer.mPreviousData = null;
+ if (data == null) {
+ data = mHistoricalLog[mNextHistoricalSlot];
+ if (data == null) {
+ data = new HistoricalData();
+ }
+ }
+ data.update(buffer.mPackageName, buffer.mUid, buffer.mProcessBuffer);
+ buffer.closeAllBuffers();
+
+ mHistoricalLog[mNextHistoricalSlot] = data;
+ mNextHistoricalSlot = (mNextHistoricalSlot + 1) % mHistoricalLog.length;
+ }
+
+ private ActiveBuffer fetchActiveBuffersLocked(IBinder token, int uid, int pid,
+ String packageName) throws RemoteException {
+ int size = mActive.size();
+ for (int i = 0; i < size; i++) {
+ ActiveBuffer buffers = mActive.get(i);
+ if (buffers.mPid == pid
+ && buffers.mUid == uid) {
+ return buffers;
+ }
+ }
+ // Didn't find one, need to create it
+ try {
+ ActiveBuffer buffers = new ActiveBuffer(token, uid, pid, packageName);
+ mActive.add(buffers);
+ return buffers;
+ } catch (IOException ex) {
+ throw new RemoteException("Failed to allocate space");
+ }
+ }
+
+ private HistoricalData removeHistoricalDataLocked(int uid, String packageName) {
+ for (int i = 0; i < mHistoricalLog.length; i++) {
+ final HistoricalData data = mHistoricalLog[i];
+ if (data != null && data.mUid == uid
+ && data.mPackageName.equals(packageName)) {
+ if (i == mNextHistoricalSlot) {
+ mHistoricalLog[i] = null;
+ } else {
+ mHistoricalLog[i] = mHistoricalLog[mNextHistoricalSlot];
+ mHistoricalLog[mNextHistoricalSlot] = null;
+ }
+ return data;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+ synchronized (mLock) {
+ for (int i = 0; i < mActive.size(); i++) {
+ final ActiveBuffer buffer = mActive.get(i);
+ fout.print("Package: ");
+ fout.print(buffer.mPackageName);
+ fout.flush();
+ try {
+ buffer.mProcessBuffer.readBytes(mTempBuffer, 0, 0, ASHMEM_SIZE);
+ ThreadedRenderer.dumpProfileData(mTempBuffer, fd);
+ } catch (IOException e) {
+ fout.println("Failed to dump");
+ }
+ fout.println();
+ }
+ for (HistoricalData buffer : mHistoricalLog) {
+ if (buffer == null) continue;
+ fout.print("Package: ");
+ fout.print(buffer.mPackageName);
+ fout.flush();
+ ThreadedRenderer.dumpProfileData(buffer.mBuffer, fd);
+ fout.println();
+ }
+ }
+ }
+
+ private final class ActiveBuffer implements DeathRecipient {
+ final int mUid;
+ final int mPid;
+ final String mPackageName;
+ final IBinder mToken;
+ MemoryFile mProcessBuffer;
+ HistoricalData mPreviousData;
+
+ ActiveBuffer(IBinder token, int uid, int pid, String packageName)
+ throws RemoteException, IOException {
+ mUid = uid;
+ mPid = pid;
+ mPackageName = packageName;
+ mToken = token;
+ mToken.linkToDeath(this, 0);
+ mProcessBuffer = new MemoryFile("GFXStats-" + uid, ASHMEM_SIZE);
+ mPreviousData = removeHistoricalDataLocked(mUid, mPackageName);
+ if (mPreviousData != null) {
+ mProcessBuffer.writeBytes(mPreviousData.mBuffer, 0, 0, ASHMEM_SIZE);
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ mToken.unlinkToDeath(this, 0);
+ processDied(this);
+ }
+
+ void closeAllBuffers() {
+ if (mProcessBuffer != null) {
+ mProcessBuffer.close();
+ mProcessBuffer = null;
+ }
+ }
+ }
+
+ private final static class HistoricalData {
+ final byte[] mBuffer = new byte[ASHMEM_SIZE];
+ int mUid;
+ String mPackageName;
+
+ void update(String packageName, int uid, MemoryFile file) {
+ mUid = uid;
+ mPackageName = packageName;
+ try {
+ file.readBytes(mBuffer, 0, 0, ASHMEM_SIZE);
+ } catch (IOException e) {}
+ }
+ }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ae2c54b..2effb44 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -925,6 +925,11 @@ public final class SystemServer {
}
}
+ if (!disableNonCoreServices) {
+ ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
+ new GraphicsStatsService(context));
+ }
+
if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}