Refactor GraphicsStatsService for updateability
Move GraphicsStatsService to android.graphics package.
Move GraphicsStatsService JNI from libservices.core to
libandroid_runtime.
Declare GraphicsStatsService ctor as the only @SystemApi.
Remove MemoryFile usage from GraphicsStatsService, but use
SharedMemory and other SDK APIs instead. This is done to
avoid using unstable API MemoryFile.getFileDescriptor.
Propose new SharedMemory.getFdDup API for next release, which
is hidden for now.
Refactor statsd puller to avoid proto serialization by moving
data directly into AStatsEventList.
"libprotoutil" is added as a static dependancy to libhwui, which
should be fine because its implementation does not link anything.
Bug: 146353313
Test: Ran "adb shell cmd stats pull-source 10068"
Test: Passed unit tests and GraphicsStatsValidationTest CTS
Change-Id: If16c5addbd519cba33e03bd84ac312595032e0e1
diff --git a/Android.bp b/Android.bp
index 69d654f..f63e78b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -445,13 +445,6 @@
}
filegroup {
- name: "graphicsstats_proto",
- srcs: [
- "libs/hwui/protos/graphicsstats.proto",
- ],
-}
-
-filegroup {
name: "libvibrator_aidl",
srcs: [
"core/java/android/os/IExternalVibrationController.aidl",
diff --git a/core/java/android/os/SharedMemory.java b/core/java/android/os/SharedMemory.java
index 26d9c7d..7512352 100644
--- a/core/java/android/os/SharedMemory.java
+++ b/core/java/android/os/SharedMemory.java
@@ -27,6 +27,7 @@
import java.io.Closeable;
import java.io.FileDescriptor;
+import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.DirectByteBuffer;
import java.nio.NioUtils;
@@ -272,6 +273,20 @@
dest.writeFileDescriptor(mFileDescriptor);
}
+ /**
+ * Returns a dup'd ParcelFileDescriptor from the SharedMemory FileDescriptor.
+ * This obeys standard POSIX semantics, where the
+ * new file descriptor shared state such as file position with the
+ * original file descriptor.
+ * TODO: propose this method as a public or system API for next release to achieve parity with
+ * NDK ASharedMemory_dupFromJava.
+ *
+ * @hide
+ */
+ public ParcelFileDescriptor getFdDup() throws IOException {
+ return ParcelFileDescriptor.dup(mFileDescriptor);
+ }
+
public static final @android.annotation.NonNull Parcelable.Creator<SharedMemory> CREATOR =
new Parcelable.Creator<SharedMemory>() {
@Override
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 35eb0fc..04c1c58 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -182,6 +182,7 @@
"android_hardware_UsbRequest.cpp",
"android_hardware_location_ActivityRecognitionHardware.cpp",
"android_util_FileObserver.cpp",
+ "android/graphics/GraphicsStatsService.cpp",
"android/graphics/SurfaceTexture.cpp",
"android/opengl/poly_clip.cpp", // TODO: .arm
"android/opengl/util.cpp",
@@ -273,6 +274,7 @@
"libstats_jni",
"libstatslog",
"server_configurable_flags",
+ "libstatspull",
],
export_shared_lib_headers: [
// AndroidRuntime.h depends on nativehelper/jni.h
diff --git a/core/jni/android/graphics/GraphicsStatsService.cpp b/core/jni/android/graphics/GraphicsStatsService.cpp
new file mode 100644
index 0000000..ef0aacc
--- /dev/null
+++ b/core/jni/android/graphics/GraphicsStatsService.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "GraphicsStatsService"
+
+#include <JankTracker.h>
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include <service/GraphicsStatsService.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using namespace android::uirenderer;
+
+static jint getAshmemSize(JNIEnv*, jobject) {
+ return sizeof(ProfileData);
+}
+
+static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
+ GraphicsStatsService::Dump* dump =
+ GraphicsStatsService::createDump(fd,
+ isProto ? GraphicsStatsService::DumpType::Protobuf
+ : GraphicsStatsService::DumpType::Text);
+ return reinterpret_cast<jlong>(dump);
+}
+
+static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ std::string path;
+ const ProfileData* data = nullptr;
+ LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
+ ScopedByteArrayRO buffer{env};
+ if (jdata != nullptr) {
+ buffer.reset(jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ data = reinterpret_cast<const ProfileData*>(buffer.get());
+ }
+ if (jpath != nullptr) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(),
+ "Failed to get path chars");
+ path.assign(pathChars.c_str(), pathChars.size());
+ }
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
+
+ const std::string package(packageChars.c_str(), packageChars.size());
+ GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
+}
+
+static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ const std::string path(pathChars.c_str(), pathChars.size());
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::addToDump(dump, path);
+}
+
+static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ GraphicsStatsService::finishDump(dump);
+}
+
+static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
+ jboolean lastFullDay) {
+ GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
+ AStatsEventList* data = reinterpret_cast<AStatsEventList*>(pulledData);
+ GraphicsStatsService::finishDumpInMemory(dump, data, lastFullDay == JNI_TRUE);
+}
+
+static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
+ jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
+ ScopedByteArrayRO buffer(env, jdata);
+ LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
+ "Buffer size %zu doesn't match expected %zu!", buffer.size(),
+ sizeof(ProfileData));
+ ScopedUtfChars pathChars(env, jpath);
+ LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
+ ScopedUtfChars packageChars(env, jpackage);
+ LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(),
+ "Failed to get path chars");
+
+ const std::string path(pathChars.c_str(), pathChars.size());
+ const std::string package(packageChars.c_str(), packageChars.size());
+ const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
+ GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
+}
+
+static jobject gGraphicsStatsServiceObject = nullptr;
+static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
+
+static JNIEnv* getJNIEnv() {
+ JavaVM* vm = AndroidRuntime::getJavaVM();
+ JNIEnv* env = nullptr;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
+ LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
+ }
+ }
+ return env;
+}
+
+// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
+static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
+ AStatsEventList* data,
+ void* cookie) {
+ JNIEnv* env = getJNIEnv();
+ if (!env) {
+ return false;
+ }
+ if (gGraphicsStatsServiceObject == nullptr) {
+ ALOGE("Failed to get graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+
+ for (bool lastFullDay : {true, false}) {
+ env->CallVoidMethod(gGraphicsStatsServiceObject,
+ gGraphicsStatsService_pullGraphicsStatsMethodID,
+ (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE),
+ reinterpret_cast<jlong>(data));
+ if (env->ExceptionCheck()) {
+ env->ExceptionDescribe();
+ env->ExceptionClear();
+ ALOGE("Failed to invoke graphicsstats service");
+ return AStatsManager_PULL_SKIP;
+ }
+ }
+ return AStatsManager_PULL_SUCCESS;
+}
+
+// Register a puller for GRAPHICS_STATS atom with the statsd service.
+static void nativeInit(JNIEnv* env, jobject javaObject) {
+ gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
+ AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
+ AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
+ AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
+
+ AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
+ &graphicsStatsPullCallback, metadata, nullptr);
+
+ AStatsManager_PullAtomMetadata_release(metadata);
+}
+
+static void nativeDestructor(JNIEnv* env, jobject javaObject) {
+ AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
+ env->DeleteGlobalRef(gGraphicsStatsServiceObject);
+ gGraphicsStatsServiceObject = nullptr;
+}
+
+static const JNINativeMethod sMethods[] =
+ {{"nGetAshmemSize", "()I", (void*)getAshmemSize},
+ {"nCreateDump", "(IZ)J", (void*)createDump},
+ {"nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)addToDump},
+ {"nAddToDump", "(JLjava/lang/String;)V", (void*)addFileToDump},
+ {"nFinishDump", "(J)V", (void*)finishDump},
+ {"nFinishDumpInMemory", "(JJZ)V", (void*)finishDumpInMemory},
+ {"nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*)saveBuffer},
+ {"nativeInit", "()V", (void*)nativeInit},
+ {"nativeDestructor", "()V", (void*)nativeDestructor}};
+
+int register_android_graphics_GraphicsStatsService(JNIEnv* env) {
+ jclass graphicsStatsService_class =
+ FindClassOrDie(env, "android/graphics/GraphicsStatsService");
+ gGraphicsStatsService_pullGraphicsStatsMethodID =
+ GetMethodIDOrDie(env, graphicsStatsService_class, "pullGraphicsStats", "(ZJ)V");
+ return jniRegisterNativeMethods(env, "android/graphics/GraphicsStatsService", sMethods,
+ NELEM(sMethods));
+}
+
+} // namespace android
diff --git a/services/core/java/com/android/server/GraphicsStatsService.java b/graphics/java/android/graphics/GraphicsStatsService.java
similarity index 85%
rename from services/core/java/com/android/server/GraphicsStatsService.java
rename to graphics/java/android/graphics/GraphicsStatsService.java
index 5179fa7..8dfd6ee 100644
--- a/services/core/java/com/android/server/GraphicsStatsService.java
+++ b/graphics/java/android/graphics/GraphicsStatsService.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.server;
+package android.graphics;
+import android.annotation.SystemApi;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.content.Context;
@@ -26,13 +27,14 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
-import android.os.MemoryFile;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.os.SharedMemory;
import android.os.Trace;
import android.os.UserHandle;
+import android.system.ErrnoException;
import android.util.Log;
import android.view.IGraphicsStats;
import android.view.IGraphicsStatsCallback;
@@ -45,6 +47,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
@@ -84,8 +87,8 @@
// This isn't static because we need this to happen after registerNativeMethods, however
// the class is loaded (and thus static ctor happens) before that occurs.
- private final int ASHMEM_SIZE = nGetAshmemSize();
- private final byte[] ZERO_DATA = new byte[ASHMEM_SIZE];
+ private final int mAshmemSize = nGetAshmemSize();
+ private final byte[] mZeroData = new byte[mAshmemSize];
private final Context mContext;
private final AppOpsManager mAppOps;
@@ -97,6 +100,7 @@
private Handler mWriteOutHandler;
private boolean mRotateIsScheduled = false;
+ @SystemApi
public GraphicsStatsService(Context context) {
mContext = context;
mAppOps = context.getSystemService(AppOpsManager.class);
@@ -108,7 +112,8 @@
throw new IllegalStateException("Graphics stats directory does not exist: "
+ mGraphicsStatsDir.getAbsolutePath());
}
- HandlerThread bgthread = new HandlerThread("GraphicsStats-disk", Process.THREAD_PRIORITY_BACKGROUND);
+ HandlerThread bgthread = new HandlerThread("GraphicsStats-disk",
+ Process.THREAD_PRIORITY_BACKGROUND);
bgthread.start();
mWriteOutHandler = new Handler(bgthread.getLooper(), new Handler.Callback() {
@@ -159,7 +164,7 @@
active.mCallback.onRotateGraphicsStatsBuffer();
} catch (RemoteException e) {
Log.w(TAG, String.format("Failed to notify '%s' (pid=%d) to rotate buffers",
- active.mInfo.packageName, active.mPid), e);
+ active.mInfo.mPackageName, active.mPid), e);
}
}
// Give a few seconds for everyone to rotate before doing the cleanup
@@ -167,8 +172,8 @@
}
@Override
- public ParcelFileDescriptor requestBufferForProcess(String packageName, IGraphicsStatsCallback token)
- throws RemoteException {
+ public ParcelFileDescriptor requestBufferForProcess(String packageName,
+ IGraphicsStatsCallback token) throws RemoteException {
int uid = Binder.getCallingUid();
int pid = Binder.getCallingPid();
ParcelFileDescriptor pfd = null;
@@ -196,7 +201,7 @@
// current day.
// This method is invoked from native code only.
@SuppressWarnings({"UnusedDeclaration"})
- private long pullGraphicsStats(boolean lastFullDay) throws RemoteException {
+ private void pullGraphicsStats(boolean lastFullDay, long pulledData) throws RemoteException {
int uid = Binder.getCallingUid();
// DUMP and PACKAGE_USAGE_STATS permissions are required to invoke this method.
@@ -213,13 +218,13 @@
long callingIdentity = Binder.clearCallingIdentity();
try {
- return pullGraphicsStatsImpl(lastFullDay);
+ pullGraphicsStatsImpl(lastFullDay, pulledData);
} finally {
Binder.restoreCallingIdentity(callingIdentity);
}
}
- private long pullGraphicsStatsImpl(boolean lastFullDay) {
+ private void pullGraphicsStatsImpl(boolean lastFullDay, long pulledData) {
long targetDay;
if (lastFullDay) {
// Get stats from yesterday. Stats stay constant, because the day is over.
@@ -235,7 +240,7 @@
buffers = new ArrayList<>(mActive.size());
for (int i = 0; i < mActive.size(); i++) {
ActiveBuffer buffer = mActive.get(i);
- if (buffer.mInfo.startTime == targetDay) {
+ if (buffer.mInfo.mStartTime == targetDay) {
try {
buffers.add(new HistoricalBuffer(buffer));
} catch (IOException ex) {
@@ -267,18 +272,7 @@
}
}
} finally {
- return nFinishDumpInMemory(dump);
- }
- }
-
- private ParcelFileDescriptor getPfd(MemoryFile file) {
- try {
- if (!file.getFileDescriptor().valid()) {
- throw new IllegalStateException("Invalid file descriptor");
- }
- return ParcelFileDescriptor.dup(file.getFileDescriptor());
- } catch (IOException ex) {
- throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ nFinishDumpInMemory(dump, pulledData, lastFullDay);
}
}
@@ -286,7 +280,7 @@
int uid, int pid, String packageName, long versionCode) throws RemoteException {
ActiveBuffer buffer = fetchActiveBuffersLocked(token, uid, pid, packageName, versionCode);
scheduleRotateLocked();
- return getPfd(buffer.mProcessBuffer);
+ return buffer.getPfd();
}
private Calendar normalizeDate(long timestamp) {
@@ -301,13 +295,15 @@
private File pathForApp(BufferInfo info) {
String subPath = String.format("%d/%s/%d/total",
- normalizeDate(info.startTime).getTimeInMillis(), info.packageName, info.versionCode);
+ normalizeDate(info.mStartTime).getTimeInMillis(), info.mPackageName,
+ info.mVersionCode);
return new File(mGraphicsStatsDir, subPath);
}
private void saveBuffer(HistoricalBuffer buffer) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) {
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "saving graphicsstats for " + buffer.mInfo.packageName);
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER,
+ "saving graphicsstats for " + buffer.mInfo.mPackageName);
}
synchronized (mFileAccessLock) {
File path = pathForApp(buffer.mInfo);
@@ -317,8 +313,9 @@
Log.w(TAG, "Unable to create path: '" + parent.getAbsolutePath() + "'");
return;
}
- nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.packageName, buffer.mInfo.versionCode,
- buffer.mInfo.startTime, buffer.mInfo.endTime, buffer.mData);
+ nSaveBuffer(path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
+ buffer.mData);
}
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
}
@@ -365,7 +362,7 @@
HistoricalBuffer data = new HistoricalBuffer(buffer);
Message.obtain(mWriteOutHandler, SAVE_BUFFER, data).sendToTarget();
} catch (IOException e) {
- Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.packageName, e);
+ Log.w(TAG, "Failed to copy graphicsstats from " + buffer.mInfo.mPackageName, e);
}
buffer.closeAllBuffers();
}
@@ -386,7 +383,7 @@
if (buffer.mPid == pid
&& buffer.mUid == uid) {
// If the buffer is too old we remove it and return a new one
- if (buffer.mInfo.startTime < today) {
+ if (buffer.mInfo.mStartTime < today) {
buffer.binderDied();
break;
} else {
@@ -410,8 +407,8 @@
HistoricalBuffer buffer = buffers.get(i);
File path = pathForApp(buffer.mInfo);
skipFiles.add(path);
- nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.packageName,
- buffer.mInfo.versionCode, buffer.mInfo.startTime, buffer.mInfo.endTime,
+ nAddToDump(dump, path.getAbsolutePath(), buffer.mInfo.mPackageName,
+ buffer.mInfo.mVersionCode, buffer.mInfo.mStartTime, buffer.mInfo.mEndTime,
buffer.mData);
}
return skipFiles;
@@ -478,20 +475,20 @@
long versionCode, long startTime, long endTime, byte[] data);
private static native void nAddToDump(long dump, String path);
private static native void nFinishDump(long dump);
- private static native long nFinishDumpInMemory(long dump);
+ private static native void nFinishDumpInMemory(long dump, long pulledData, boolean lastFullDay);
private static native void nSaveBuffer(String path, String packageName, long versionCode,
long startTime, long endTime, byte[] data);
private final class BufferInfo {
- final String packageName;
- final long versionCode;
- long startTime;
- long endTime;
+ final String mPackageName;
+ final long mVersionCode;
+ long mStartTime;
+ long mEndTime;
BufferInfo(String packageName, long versionCode, long startTime) {
- this.packageName = packageName;
- this.versionCode = versionCode;
- this.startTime = startTime;
+ this.mPackageName = packageName;
+ this.mVersionCode = versionCode;
+ this.mStartTime = startTime;
}
}
@@ -501,7 +498,8 @@
final int mPid;
final IGraphicsStatsCallback mCallback;
final IBinder mToken;
- MemoryFile mProcessBuffer;
+ SharedMemory mProcessBuffer;
+ ByteBuffer mMapping;
ActiveBuffer(IGraphicsStatsCallback token, int uid, int pid, String packageName,
long versionCode)
@@ -512,8 +510,14 @@
mCallback = token;
mToken = mCallback.asBinder();
mToken.linkToDeath(this, 0);
- mProcessBuffer = new MemoryFile("GFXStats-" + pid, ASHMEM_SIZE);
- mProcessBuffer.writeBytes(ZERO_DATA, 0, 0, ASHMEM_SIZE);
+ try {
+ mProcessBuffer = SharedMemory.create("GFXStats-" + pid, mAshmemSize);
+ mMapping = mProcessBuffer.mapReadWrite();
+ } catch (ErrnoException ex) {
+ ex.rethrowAsIOException();
+ }
+ mMapping.position(0);
+ mMapping.put(mZeroData, 0, mAshmemSize);
}
@Override
@@ -523,20 +527,40 @@
}
void closeAllBuffers() {
+ if (mMapping != null) {
+ SharedMemory.unmap(mMapping);
+ mMapping = null;
+ }
if (mProcessBuffer != null) {
mProcessBuffer.close();
mProcessBuffer = null;
}
}
+
+ ParcelFileDescriptor getPfd() {
+ try {
+ return mProcessBuffer.getFdDup();
+ } catch (IOException ex) {
+ throw new IllegalStateException("Failed to get PFD from memory file", ex);
+ }
+ }
+
+ void readBytes(byte[] buffer, int count) throws IOException {
+ if (mMapping == null) {
+ throw new IOException("SharedMemory has been deactivated");
+ }
+ mMapping.position(0);
+ mMapping.get(buffer, 0, count);
+ }
}
private final class HistoricalBuffer {
final BufferInfo mInfo;
- final byte[] mData = new byte[ASHMEM_SIZE];
+ final byte[] mData = new byte[mAshmemSize];
HistoricalBuffer(ActiveBuffer active) throws IOException {
mInfo = active.mInfo;
- mInfo.endTime = System.currentTimeMillis();
- active.mProcessBuffer.readBytes(mData, 0, 0, ASHMEM_SIZE);
+ mInfo.mEndTime = System.currentTimeMillis();
+ active.readBytes(mData, mAshmemSize);
}
}
}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 51270f5..301d1af 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -92,9 +92,12 @@
"libandroidfw",
"libcrypto",
"libsync",
+ "libstatspull",
+ "libstatssocket",
],
static_libs: [
"libEGL_blobCache",
+ "libprotoutil",
],
},
host: {
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index c418617..644d5fb 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -26,9 +26,9 @@
#include <sys/types.h>
#include <unistd.h>
-#include <algorithm>
-#include <map>
-#include <vector>
+#include <android/util/ProtoOutputStream.h>
+#include <stats_event.h>
+#include <statslog.h>
#include "JankTracker.h"
#include "protos/graphicsstats.pb.h"
@@ -61,7 +61,7 @@
}
}
bool valid() { return mFd != -1; }
- operator int() { return mFd; } // NOLINT(google-explicit-constructor)
+ operator int() { return mFd; } // NOLINT(google-explicit-constructor)
private:
int mFd;
@@ -485,79 +485,82 @@
delete dump;
}
-class MemOutputStreamLite : public io::ZeroCopyOutputStream {
-public:
- explicit MemOutputStreamLite() : mCopyAdapter(), mImpl(&mCopyAdapter) {}
- virtual ~MemOutputStreamLite() {}
+using namespace google::protobuf;
- virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
+// Field ids taken from FrameTimingHistogram message in atoms.proto
+#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1
+#define FRAME_COUNTS_FIELD_NUMBER 2
- virtual void BackUp(int count) override { mImpl.BackUp(count); }
-
- virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
-
- bool Flush() { return mImpl.Flush(); }
-
- void copyData(const DumpMemoryFn& reader, void* param1, void* param2) {
- int bufferOffset = 0;
- int totalSize = mCopyAdapter.mBuffersSize - mCopyAdapter.mCurrentBufferUnusedSize;
- int totalDataLeft = totalSize;
- for (auto& it : mCopyAdapter.mBuffers) {
- int bufferSize = std::min(totalDataLeft, (int)it.size()); // last buffer is not full
- reader(it.data(), bufferOffset, bufferSize, totalSize, param1, param2);
- bufferOffset += bufferSize;
- totalDataLeft -= bufferSize;
- }
+static void writeCpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
}
-
-private:
- struct MemAdapter : public io::CopyingOutputStream {
- // Data is stored in an array of buffers.
- // JNI SetByteArrayRegion assembles data in one continuous Java byte[] buffer.
- std::vector<std::vector<unsigned char>> mBuffers;
- int mBuffersSize = 0; // total bytes allocated in mBuffers
- int mCurrentBufferUnusedSize = 0; // unused bytes in the last buffer mBuffers.back()
- unsigned char* mCurrentBuffer = nullptr; // pointer to next free byte in mBuffers.back()
-
- explicit MemAdapter() {}
- virtual ~MemAdapter() {}
-
- virtual bool Write(const void* buffer, int size) override {
- while (size > 0) {
- if (0 == mCurrentBufferUnusedSize) {
- mCurrentBufferUnusedSize =
- std::max(size, mBuffersSize ? 2 * mBuffersSize : 10000);
- mBuffers.emplace_back();
- mBuffers.back().resize(mCurrentBufferUnusedSize);
- mCurrentBuffer = mBuffers.back().data();
- mBuffersSize += mCurrentBufferUnusedSize;
- }
- int dataMoved = std::min(mCurrentBufferUnusedSize, size);
- memcpy(mCurrentBuffer, buffer, dataMoved);
- mCurrentBufferUnusedSize -= dataMoved;
- mCurrentBuffer += dataMoved;
- buffer = reinterpret_cast<const unsigned char*>(buffer) + dataMoved;
- size -= dataMoved;
- }
- return true;
- }
- };
-
- MemOutputStreamLite::MemAdapter mCopyAdapter;
- io::CopyingOutputStreamAdaptor mImpl;
-};
-
-void GraphicsStatsService::finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2) {
- MemOutputStreamLite stream;
- dump->updateProto();
- bool success = dump->proto().SerializeToZeroCopyStream(&stream) && stream.Flush();
- delete dump;
- if (!success) {
- return;
+ for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
+ auto& bucket = stat.histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
}
- stream.copyData(reader, param1, param2);
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
}
+static void writeGpuHistogram(AStatsEvent* event,
+ const uirenderer::protos::GraphicsStatsProto& stat) {
+ util::ProtoOutputStream proto;
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
+ TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
+ (int)bucket.render_millis());
+ }
+ for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
+ auto& bucket = stat.gpu_histogram(bucketIndex);
+ proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
+ FRAME_COUNTS_FIELD_NUMBER /* field id */,
+ (long long)bucket.frame_count());
+ }
+ std::vector<uint8_t> outVector;
+ proto.serializeToVector(&outVector);
+ AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
+}
+
+
+void GraphicsStatsService::finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay) {
+ dump->updateProto();
+ auto& serviceDump = dump->proto();
+ for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) {
+ auto& stat = serviceDump.stats(stat_index);
+ AStatsEvent* event = AStatsEventList_addStatsEvent(data);
+ AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS);
+ AStatsEvent_writeString(event, stat.package_name().c_str());
+ AStatsEvent_writeInt64(event, (int64_t)stat.version_code());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_start());
+ AStatsEvent_writeInt64(event, (int64_t)stat.stats_end());
+ AStatsEvent_writeInt32(event, (int32_t)stat.pipeline());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count());
+ AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count());
+ writeCpuHistogram(event, stat);
+ writeGpuHistogram(event, stat);
+ // TODO: fill in UI mainline module version, when the feature is available.
+ AStatsEvent_writeInt64(event, (int64_t)0);
+ AStatsEvent_writeBool(event, !lastFullDay);
+ AStatsEvent_build(event);
+ }
+}
+
+
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index 4bed9633..59e21d0 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -20,6 +20,7 @@
#include "JankTracker.h"
#include "utils/Macros.h"
+#include <stats_pull_atom_callback.h>
namespace android {
namespace uirenderer {
@@ -27,9 +28,6 @@
class GraphicsStatsProto;
}
-typedef void (*DumpMemoryFn)(void* buffer, int bufferOffset, int bufferSize, int totalSize,
- void* param1, void* param2);
-
/*
* The exported entry points used by GraphicsStatsService.java in f/b/services/core
*
@@ -56,8 +54,8 @@
int64_t startTime, int64_t endTime, const ProfileData* data);
ANDROID_API static void addToDump(Dump* dump, const std::string& path);
ANDROID_API static void finishDump(Dump* dump);
- ANDROID_API static void finishDumpInMemory(Dump* dump, const DumpMemoryFn& reader, void* param1,
- void* param2);
+ ANDROID_API static void finishDumpInMemory(Dump* dump, AStatsEventList* data,
+ bool lastFullDay);
// Visible for testing
static bool parseFromFile(const std::string& path, protos::GraphicsStatsProto* output);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 812bc43..49c7e0a3 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -13,7 +13,6 @@
],
srcs: [
- ":graphicsstats_proto",
":lib_alarmManagerService_native",
"BroadcastRadio/JavaRef.cpp",
"BroadcastRadio/NativeCallbackThread.cpp",
@@ -53,7 +52,6 @@
"com_android_server_UsbHostManager.cpp",
"com_android_server_VibratorService.cpp",
"com_android_server_PersistentDataBlockService.cpp",
- "com_android_server_GraphicsStatsService.cpp",
"com_android_server_am_CachedAppOptimizer.cpp",
"com_android_server_am_LowMemDetector.cpp",
"com_android_server_incremental_IncrementalManagerService.cpp",
@@ -107,8 +105,6 @@
"libinputflinger",
"libinputflinger_base",
"libinputservice",
- "libprotobuf-cpp-lite",
- "libprotoutil",
"libstatshidl",
"libstatspull",
"libstatssocket",
diff --git a/services/core/jni/com_android_server_GraphicsStatsService.cpp b/services/core/jni/com_android_server_GraphicsStatsService.cpp
deleted file mode 100644
index aa7067e..0000000
--- a/services/core/jni/com_android_server_GraphicsStatsService.cpp
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#define LOG_TAG "GraphicsStatsService"
-
-#include <jni.h>
-#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include <JankTracker.h>
-#include <service/GraphicsStatsService.h>
-#include <stats_pull_atom_callback.h>
-#include <stats_event.h>
-#include <statslog.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
-#include <android/util/ProtoOutputStream.h>
-#include "android/graphics/Utils.h"
-#include "core_jni_helpers.h"
-#include "protos/graphicsstats.pb.h"
-#include <cstring>
-#include <memory>
-
-namespace android {
-
-using namespace android::uirenderer;
-
-static jint getAshmemSize(JNIEnv*, jobject) {
- return sizeof(ProfileData);
-}
-
-static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
- GraphicsStatsService::Dump* dump = GraphicsStatsService::createDump(fd, isProto
- ? GraphicsStatsService::DumpType::Protobuf : GraphicsStatsService::DumpType::Text);
- return reinterpret_cast<jlong>(dump);
-}
-
-static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstring jpackage,
- jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
- std::string path;
- const ProfileData* data = nullptr;
- LOG_ALWAYS_FATAL_IF(jdata == nullptr && jpath == nullptr, "Path and data can't both be null");
- ScopedByteArrayRO buffer{env};
- if (jdata != nullptr) {
- buffer.reset(jdata);
- LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
- "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
- data = reinterpret_cast<const ProfileData*>(buffer.get());
- }
- if (jpath != nullptr) {
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- path.assign(pathChars.c_str(), pathChars.size());
- }
- ScopedUtfChars packageChars(env, jpackage);
- LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars");
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- LOG_ALWAYS_FATAL_IF(!dump, "null passed for dump pointer");
-
- const std::string package(packageChars.c_str(), packageChars.size());
- GraphicsStatsService::addToDump(dump, path, package, versionCode, startTime, endTime, data);
-}
-
-static void addFileToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath) {
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- const std::string path(pathChars.c_str(), pathChars.size());
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- GraphicsStatsService::addToDump(dump, path);
-}
-
-static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- GraphicsStatsService::finishDump(dump);
-}
-
-static jlong finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr) {
- GraphicsStatsService::Dump* dump = reinterpret_cast<GraphicsStatsService::Dump*>(dumpPtr);
- std::vector<uint8_t>* result = new std::vector<uint8_t>();
- GraphicsStatsService::finishDumpInMemory(dump,
- [](void* buffer, int bufferOffset, int bufferSize, int totalSize, void* param1, void* param2) {
- std::vector<uint8_t>* outBuffer = reinterpret_cast<std::vector<uint8_t>*>(param2);
- if (outBuffer->size() < totalSize) {
- outBuffer->resize(totalSize);
- }
- std::memcpy(outBuffer->data() + bufferOffset, buffer, bufferSize);
- }, env, result);
- return reinterpret_cast<jlong>(result);
-}
-
-static void saveBuffer(JNIEnv* env, jobject clazz, jstring jpath, jstring jpackage,
- jlong versionCode, jlong startTime, jlong endTime, jbyteArray jdata) {
- ScopedByteArrayRO buffer(env, jdata);
- LOG_ALWAYS_FATAL_IF(buffer.size() != sizeof(ProfileData),
- "Buffer size %zu doesn't match expected %zu!", buffer.size(), sizeof(ProfileData));
- ScopedUtfChars pathChars(env, jpath);
- LOG_ALWAYS_FATAL_IF(pathChars.size() <= 0 || !pathChars.c_str(), "Failed to get path chars");
- ScopedUtfChars packageChars(env, jpackage);
- LOG_ALWAYS_FATAL_IF(packageChars.size() <= 0 || !packageChars.c_str(), "Failed to get path chars");
-
- const std::string path(pathChars.c_str(), pathChars.size());
- const std::string package(packageChars.c_str(), packageChars.size());
- const ProfileData* data = reinterpret_cast<const ProfileData*>(buffer.get());
- GraphicsStatsService::saveBuffer(path, package, versionCode, startTime, endTime, data);
-}
-
-static jobject gGraphicsStatsServiceObject = nullptr;
-static jmethodID gGraphicsStatsService_pullGraphicsStatsMethodID;
-
-static JNIEnv* getJNIEnv() {
- JavaVM* vm = AndroidRuntime::getJavaVM();
- JNIEnv* env = nullptr;
- if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
- if (vm->AttachCurrentThreadAsDaemon(&env, nullptr) != JNI_OK) {
- LOG_ALWAYS_FATAL("Failed to AttachCurrentThread!");
- }
- }
- return env;
-}
-
-using namespace google::protobuf;
-
-// Field ids taken from FrameTimingHistogram message in atoms.proto
-#define TIME_MILLIS_BUCKETS_FIELD_NUMBER 1
-#define FRAME_COUNTS_FIELD_NUMBER 2
-
-static void writeCpuHistogram(AStatsEvent* event,
- const uirenderer::protos::GraphicsStatsProto& stat) {
- util::ProtoOutputStream proto;
- for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
- auto& bucket = stat.histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
- TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
- (int)bucket.render_millis());
- }
- for (int bucketIndex = 0; bucketIndex < stat.histogram_size(); bucketIndex++) {
- auto& bucket = stat.histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- FRAME_COUNTS_FIELD_NUMBER /* field id */,
- (long long)bucket.frame_count());
- }
- std::vector<uint8_t> outVector;
- proto.serializeToVector(&outVector);
- AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
-}
-
-static void writeGpuHistogram(AStatsEvent* event,
- const uirenderer::protos::GraphicsStatsProto& stat) {
- util::ProtoOutputStream proto;
- for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
- auto& bucket = stat.gpu_histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT32 | android::util::FIELD_COUNT_REPEATED |
- TIME_MILLIS_BUCKETS_FIELD_NUMBER /* field id */,
- (int)bucket.render_millis());
- }
- for (int bucketIndex = 0; bucketIndex < stat.gpu_histogram_size(); bucketIndex++) {
- auto& bucket = stat.gpu_histogram(bucketIndex);
- proto.write(android::util::FIELD_TYPE_INT64 | android::util::FIELD_COUNT_REPEATED |
- FRAME_COUNTS_FIELD_NUMBER /* field id */,
- (long long)bucket.frame_count());
- }
- std::vector<uint8_t> outVector;
- proto.serializeToVector(&outVector);
- AStatsEvent_writeByteArray(event, outVector.data(), outVector.size());
-}
-
-// graphicsStatsPullCallback is invoked by statsd service to pull GRAPHICS_STATS atom.
-static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t atom_tag,
- AStatsEventList* data,
- void* cookie) {
- JNIEnv* env = getJNIEnv();
- if (!env) {
- return false;
- }
- if (gGraphicsStatsServiceObject == nullptr) {
- ALOGE("Failed to get graphicsstats service");
- return AStatsManager_PULL_SKIP;
- }
-
- for (bool lastFullDay : {true, false}) {
- jlong jdata = (jlong) env->CallLongMethod(
- gGraphicsStatsServiceObject,
- gGraphicsStatsService_pullGraphicsStatsMethodID,
- (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE));
- if (env->ExceptionCheck()) {
- env->ExceptionDescribe();
- env->ExceptionClear();
- ALOGE("Failed to invoke graphicsstats service");
- return AStatsManager_PULL_SKIP;
- }
- if (!jdata) {
- // null means data is not available for that day.
- continue;
- }
- android::uirenderer::protos::GraphicsStatsServiceDumpProto serviceDump;
- std::vector<uint8_t>* buffer = reinterpret_cast<std::vector<uint8_t>*>(jdata);
- std::unique_ptr<std::vector<uint8_t>> bufferRelease(buffer);
- int dataSize = buffer->size();
- if (!dataSize) {
- // Data is not available for that day.
- continue;
- }
- io::ArrayInputStream input{buffer->data(), dataSize};
- bool success = serviceDump.ParseFromZeroCopyStream(&input);
- if (!success) {
- ALOGW("Parse failed on GraphicsStatsPuller error='%s' dataSize='%d'",
- serviceDump.InitializationErrorString().c_str(), dataSize);
- return AStatsManager_PULL_SKIP;
- }
-
- for (int stat_index = 0; stat_index < serviceDump.stats_size(); stat_index++) {
- auto& stat = serviceDump.stats(stat_index);
- AStatsEvent* event = AStatsEventList_addStatsEvent(data);
- AStatsEvent_setAtomId(event, android::util::GRAPHICS_STATS);
- AStatsEvent_writeString(event, stat.package_name().c_str());
- AStatsEvent_writeInt64(event, (int64_t)stat.version_code());
- AStatsEvent_writeInt64(event, (int64_t)stat.stats_start());
- AStatsEvent_writeInt64(event, (int64_t)stat.stats_end());
- AStatsEvent_writeInt32(event, (int32_t)stat.pipeline());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().total_frames());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_vsync_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().high_input_latency_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_ui_thread_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_bitmap_upload_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().slow_draw_count());
- AStatsEvent_writeInt32(event, (int32_t)stat.summary().missed_deadline_count());
- writeCpuHistogram(event, stat);
- writeGpuHistogram(event, stat);
- // TODO: fill in UI mainline module version, when the feature is available.
- AStatsEvent_writeInt64(event, (int64_t)0);
- AStatsEvent_writeBool(event, !lastFullDay);
- AStatsEvent_build(event);
- }
- }
- return AStatsManager_PULL_SUCCESS;
-}
-
-// Register a puller for GRAPHICS_STATS atom with the statsd service.
-static void nativeInit(JNIEnv* env, jobject javaObject) {
- gGraphicsStatsServiceObject = env->NewGlobalRef(javaObject);
- AStatsManager_PullAtomMetadata* metadata = AStatsManager_PullAtomMetadata_obtain();
- AStatsManager_PullAtomMetadata_setCoolDownNs(metadata, 10 * 1000000); // 10 milliseconds
- AStatsManager_PullAtomMetadata_setTimeoutNs(metadata, 2 * NS_PER_SEC); // 2 seconds
-
- AStatsManager_registerPullAtomCallback(android::util::GRAPHICS_STATS,
- &graphicsStatsPullCallback, metadata, nullptr);
-
- AStatsManager_PullAtomMetadata_release(metadata);
-}
-
-static void nativeDestructor(JNIEnv* env, jobject javaObject) {
- AStatsManager_unregisterPullAtomCallback(android::util::GRAPHICS_STATS);
- env->DeleteGlobalRef(gGraphicsStatsServiceObject);
- gGraphicsStatsServiceObject = nullptr;
-}
-
-static const JNINativeMethod sMethods[] = {
- { "nGetAshmemSize", "()I", (void*) getAshmemSize },
- { "nCreateDump", "(IZ)J", (void*) createDump },
- { "nAddToDump", "(JLjava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) addToDump },
- { "nAddToDump", "(JLjava/lang/String;)V", (void*) addFileToDump },
- { "nFinishDump", "(J)V", (void*) finishDump },
- { "nFinishDumpInMemory", "(J)J", (void*) finishDumpInMemory },
- { "nSaveBuffer", "(Ljava/lang/String;Ljava/lang/String;JJJ[B)V", (void*) saveBuffer },
- { "nativeInit", "()V", (void*) nativeInit },
- { "nativeDestructor", "()V", (void*)nativeDestructor }
-};
-
-int register_android_server_GraphicsStatsService(JNIEnv* env)
-{
- jclass graphicsStatsService_class = FindClassOrDie(env,
- "com/android/server/GraphicsStatsService");
- gGraphicsStatsService_pullGraphicsStatsMethodID = GetMethodIDOrDie(env,
- graphicsStatsService_class, "pullGraphicsStats", "(Z)J");
- return jniRegisterNativeMethods(env, "com/android/server/GraphicsStatsService",
- sMethods, NELEM(sMethods));
-}
-
-} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 1202ad3..c186494 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -49,7 +49,7 @@
int register_android_server_Watchdog(JNIEnv* env);
int register_android_server_HardwarePropertiesManagerService(JNIEnv* env);
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
-int register_android_server_GraphicsStatsService(JNIEnv* env);
+int register_android_graphics_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
@@ -102,7 +102,7 @@
register_android_server_HardwarePropertiesManagerService(env);
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
- register_android_server_GraphicsStatsService(env);
+ register_android_graphics_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
register_android_server_net_NetworkStatsFactory(env);
register_android_server_net_NetworkStatsService(env);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 036335c..eef6c63 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -41,6 +41,7 @@
import android.content.res.Resources.Theme;
import android.database.sqlite.SQLiteCompatibilityWalFlags;
import android.database.sqlite.SQLiteGlobal;
+import android.graphics.GraphicsStatsService;
import android.hardware.display.DisplayManagerInternal;
import android.net.ConnectivityModuleConnector;
import android.net.ITetheringConnector;