Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0bfb6641 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor GraphicsStatsService for updateability"

parents 2ec0680f c9043817
Loading
Loading
Loading
Loading
+0 −7
Original line number Diff line number Diff line
@@ -444,13 +444,6 @@ filegroup {
    path: "core/java",
}

filegroup {
    name: "graphicsstats_proto",
    srcs: [
        "libs/hwui/protos/graphicsstats.proto",
    ],
}

filegroup {
    name: "libvibrator_aidl",
    srcs: [
+15 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import dalvik.system.VMRuntime;

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 @@ public final class SharedMemory implements Parcelable, Closeable {
        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
+2 −0
Original line number Diff line number Diff line
@@ -182,6 +182,7 @@ cc_library_shared {
                "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 @@ cc_library_shared {
                "libstats_jni",
                "libstatslog",
                "server_configurable_flags",
                "libstatspull",
            ],
            export_shared_lib_headers: [
                // AndroidRuntime.h depends on nativehelper/jni.h
+195 −0
Original line number Diff line number Diff line
@@ -16,23 +16,17 @@

#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 <JankTracker.h>
#include <service/GraphicsStatsService.h>
#include <stats_pull_atom_callback.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.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 {

@@ -43,8 +37,10 @@ static jint getAshmemSize(JNIEnv*, jobject) {
}

static jlong createDump(JNIEnv*, jobject, jint fd, jboolean isProto) {
    GraphicsStatsService::Dump* dump = GraphicsStatsService::createDump(fd, isProto
            ? GraphicsStatsService::DumpType::Protobuf : GraphicsStatsService::DumpType::Text);
    GraphicsStatsService::Dump* dump =
            GraphicsStatsService::createDump(fd,
                                             isProto ? GraphicsStatsService::DumpType::Protobuf
                                                     : GraphicsStatsService::DumpType::Text);
    return reinterpret_cast<jlong>(dump);
}

@@ -57,16 +53,19 @@ static void addToDump(JNIEnv* env, jobject, jlong dumpPtr, jstring jpath, jstrin
    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));
                            "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");
        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");
    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");

@@ -87,29 +86,24 @@ static void finishDump(JNIEnv*, jobject, jlong dumpPtr) {
    GraphicsStatsService::finishDump(dump);
}

static jlong finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr) {
static void finishDumpInMemory(JNIEnv* env, jobject, jlong dumpPtr, jlong pulledData,
                               jboolean lastFullDay) {
    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);
    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));
                        "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");
    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());
@@ -131,52 +125,6 @@ static JNIEnv* getJNIEnv() {
    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,
@@ -191,59 +139,16 @@ static AStatsManager_PullAtomCallbackReturn graphicsStatsPullCallback(int32_t at
    }

    for (bool lastFullDay : {true, false}) {
        jlong jdata = (jlong) env->CallLongMethod(
                    gGraphicsStatsServiceObject,
        env->CallVoidMethod(gGraphicsStatsServiceObject,
                            gGraphicsStatsService_pullGraphicsStatsMethodID,
                    (jboolean)(lastFullDay ? JNI_TRUE : JNI_FALSE));
                            (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;
        }
        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;
}
@@ -267,26 +172,24 @@ static void nativeDestructor(JNIEnv* env, jobject javaObject) {
    gGraphicsStatsServiceObject = nullptr;
}

static const JNINativeMethod sMethods[] = {
    { "nGetAshmemSize", "()I", (void*) getAshmemSize },
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 },
         {"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_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));
         {"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
Loading