diff options
author | John Reck <jreck@google.com> | 2015-03-18 15:24:33 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2015-03-27 11:50:56 -0700 |
commit | edc524c90506d80e0fc5fb67e8de7b8f3ef53439 (patch) | |
tree | 098c18daa80655fe0fa3faab7c39332685c163ef /services | |
parent | 1cef4196886b0cc1238111d396c1e3665a5fd2ae (diff) | |
download | frameworks_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.java | 256 | ||||
-rw-r--r-- | services/java/com/android/server/SystemServer.java | 5 |
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); } |