Merge "Reroute surfaceflinger atoms through system server" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
d07ae7b445
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
* Copyright 2020 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.
|
||||
@@ -432,6 +432,7 @@ public class StatsPullAtomService extends SystemService {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
private native void initializeNativePullers();
|
||||
/**
|
||||
* Use of this StatsPullAtomCallbackImpl means we avoid one class per tagId, which we would
|
||||
* get if we used lambdas.
|
||||
@@ -713,6 +714,7 @@ public class StatsPullAtomService extends SystemService {
|
||||
super.onBootPhase(phase);
|
||||
if (phase == PHASE_SYSTEM_SERVICES_READY) {
|
||||
BackgroundThread.getHandler().post(() -> {
|
||||
initializeNativePullers(); // Initialize pullers that need JNI.
|
||||
initializePullersState();
|
||||
registerPullers();
|
||||
registerEventListeners();
|
||||
|
||||
@@ -34,6 +34,7 @@ cc_library_static {
|
||||
"gnss/GnssMeasurement.cpp",
|
||||
"gnss/GnssMeasurementCallback.cpp",
|
||||
"gnss/Utils.cpp",
|
||||
"stats/SurfaceFlingerPuller.cpp",
|
||||
"com_android_server_adb_AdbDebuggingManager.cpp",
|
||||
"com_android_server_am_BatteryStatsService.cpp",
|
||||
"com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
|
||||
@@ -53,6 +54,7 @@ cc_library_static {
|
||||
"com_android_server_SerialService.cpp",
|
||||
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
|
||||
"com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp",
|
||||
"com_android_server_stats_pull_StatsPullAtomService.cpp",
|
||||
"com_android_server_storage_AppFuseBridge.cpp",
|
||||
"com_android_server_SystemServer.cpp",
|
||||
"com_android_server_tv_TvUinputBridge.cpp",
|
||||
@@ -127,6 +129,7 @@ cc_defaults {
|
||||
"libsensorservice",
|
||||
"libsensorservicehidl",
|
||||
"libgui",
|
||||
"libtimestats_atoms_proto",
|
||||
"libusbhost",
|
||||
"libtinyalsa",
|
||||
"libEGL",
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright 2020 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 "StatsPullAtomService"
|
||||
|
||||
#include <jni.h>
|
||||
#include <log/log.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include <stats_event.h>
|
||||
#include <stats_pull_atom_callback.h>
|
||||
#include <statslog.h>
|
||||
|
||||
#include "stats/SurfaceFlingerPuller.h"
|
||||
|
||||
namespace android {
|
||||
|
||||
static server::stats::SurfaceFlingerPuller gSurfaceFlingerPuller;
|
||||
|
||||
static AStatsManager_PullAtomCallbackReturn onSurfaceFlingerPullCallback(int32_t atom_tag,
|
||||
AStatsEventList* data,
|
||||
void* cookie) {
|
||||
return gSurfaceFlingerPuller.pull(atom_tag, data);
|
||||
}
|
||||
|
||||
static void initializeNativePullers(JNIEnv* env, jobject javaObject) {
|
||||
// Surface flinger layer & global info.
|
||||
gSurfaceFlingerPuller = server::stats::SurfaceFlingerPuller();
|
||||
AStatsManager_setPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
|
||||
/* metadata= */ nullptr, onSurfaceFlingerPullCallback,
|
||||
/* cookie= */ nullptr);
|
||||
AStatsManager_setPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
|
||||
/* metadata= */ nullptr, onSurfaceFlingerPullCallback,
|
||||
/* cookie= */ nullptr);
|
||||
}
|
||||
|
||||
static const JNINativeMethod sMethods[] = {
|
||||
{"initializeNativePullers", "()V", (void*)initializeNativePullers}};
|
||||
|
||||
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env) {
|
||||
int res = jniRegisterNativeMethods(env, "com/android/server/stats/pull/StatsPullAtomService",
|
||||
sMethods, NELEM(sMethods));
|
||||
if (res < 0) {
|
||||
ALOGE("failed to register native methods");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
@@ -61,6 +61,7 @@ int register_android_server_com_android_server_pm_PackageManagerShellCommandData
|
||||
int register_android_server_AdbDebuggingManager(JNIEnv* env);
|
||||
int register_android_server_FaceService(JNIEnv* env);
|
||||
int register_android_server_GpuService(JNIEnv* env);
|
||||
int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
|
||||
};
|
||||
|
||||
using namespace android;
|
||||
@@ -115,5 +116,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
|
||||
register_android_server_AdbDebuggingManager(env);
|
||||
register_android_server_FaceService(env);
|
||||
register_android_server_GpuService(env);
|
||||
register_android_server_stats_pull_StatsPullAtomService(env);
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
8
services/core/jni/stats/OWNERS
Normal file
8
services/core/jni/stats/OWNERS
Normal file
@@ -0,0 +1,8 @@
|
||||
jeffreyhuang@google.com
|
||||
jtnguyen@google.com
|
||||
muhammadq@google.com
|
||||
sharaieko@google.com
|
||||
singhtejinder@google.com
|
||||
tsaichristine@google.com
|
||||
yaochen@google.com
|
||||
yro@google.com
|
||||
168
services/core/jni/stats/SurfaceFlingerPuller.cpp
Normal file
168
services/core/jni/stats/SurfaceFlingerPuller.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2021 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 "SurfaceFlingerPuller"
|
||||
|
||||
#include "SurfaceFlingerPuller.h"
|
||||
|
||||
#include <gui/SurfaceComposerClient.h>
|
||||
#include <log/log.h>
|
||||
#include <statslog.h>
|
||||
#include <timestatsatomsproto/TimeStatsAtomsProtoHeader.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace android {
|
||||
namespace server {
|
||||
namespace stats {
|
||||
|
||||
using android::util::BytesField;
|
||||
using std::optional;
|
||||
|
||||
namespace {
|
||||
optional<BytesField> getBytes(const google::protobuf::MessageLite& proto, std::string& data) {
|
||||
if (!proto.SerializeToString(&data)) {
|
||||
ALOGW("Unable to serialize surface flinger bytes field");
|
||||
return std::nullopt;
|
||||
}
|
||||
return {BytesField(data.data(), data.size())};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::pull(int32_t atomTag,
|
||||
AStatsEventList* data) {
|
||||
// Don't need mutexes here, since there is no global state.
|
||||
// SurfaceComposerClient is thread safe, and surfaceflinger is internally thread safe.
|
||||
|
||||
bool success = false;
|
||||
std::string pullDataProto;
|
||||
status_t err = SurfaceComposerClient::onPullAtom(atomTag, &pullDataProto, &success);
|
||||
if (!success || err != NO_ERROR) {
|
||||
ALOGW("Failed to pull atom %" PRId32
|
||||
" from surfaceflinger. Success is %d, binder status is %s",
|
||||
atomTag, (int)success, binder::Status::exceptionToString(err).c_str());
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
|
||||
switch (atomTag) {
|
||||
case android::util::SURFACEFLINGER_STATS_GLOBAL_INFO:
|
||||
return parseGlobalInfoPull(pullDataProto, data);
|
||||
case android::util::SURFACEFLINGER_STATS_LAYER_INFO:
|
||||
return parseLayerInfoPull(pullDataProto, data);
|
||||
default:
|
||||
ALOGW("Invalid atom id for surfaceflinger pullers: %" PRId32, atomTag);
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
}
|
||||
|
||||
AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseGlobalInfoPull(
|
||||
const std::string& protoData, AStatsEventList* data) {
|
||||
android::surfaceflinger::SurfaceflingerStatsGlobalInfoWrapper atomList;
|
||||
if (!atomList.ParseFromString(protoData)) {
|
||||
ALOGW("Error parsing surface flinger global stats to proto");
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
|
||||
for (const auto& atom : atomList.atom()) {
|
||||
// The strings must outlive the BytesFields, which only have a pointer to the data.
|
||||
std::string frameDurationStr, renderEngineTimeStr, deadlineMissesStr, predictionErrorsStr;
|
||||
optional<BytesField> frameDuration = getBytes(atom.frame_duration(), frameDurationStr);
|
||||
optional<BytesField> renderEngineTime =
|
||||
getBytes(atom.render_engine_timing(), renderEngineTimeStr);
|
||||
optional<BytesField> deadlineMisses =
|
||||
getBytes(atom.sf_deadline_misses(), deadlineMissesStr);
|
||||
optional<BytesField> predictionErrors =
|
||||
getBytes(atom.sf_prediction_errors(), predictionErrorsStr);
|
||||
|
||||
// Fail if any serialization to bytes failed.
|
||||
if (!frameDuration || !renderEngineTime || !deadlineMisses || !predictionErrors) {
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
|
||||
android::util::addAStatsEvent(data, android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
|
||||
atom.total_frames(), atom.missed_frames(),
|
||||
atom.client_composition_frames(), atom.display_on_millis(),
|
||||
atom.animation_millis(), atom.event_connection_count(),
|
||||
frameDuration.value(), renderEngineTime.value(),
|
||||
atom.total_timeline_frames(), atom.total_janky_frames(),
|
||||
atom.total_janky_frames_with_long_cpu(),
|
||||
atom.total_janky_frames_with_long_gpu(),
|
||||
atom.total_janky_frames_sf_unattributed(),
|
||||
atom.total_janky_frames_app_unattributed(),
|
||||
atom.total_janky_frames_sf_scheduling(),
|
||||
atom.total_jank_frames_sf_prediction_error(),
|
||||
atom.total_jank_frames_app_buffer_stuffing(),
|
||||
atom.display_refresh_rate_bucket(), deadlineMisses.value(),
|
||||
predictionErrors.value(), atom.render_rate_bucket());
|
||||
}
|
||||
return AStatsManager_PULL_SUCCESS;
|
||||
}
|
||||
|
||||
AStatsManager_PullAtomCallbackReturn SurfaceFlingerPuller::parseLayerInfoPull(
|
||||
const std::string& protoData, AStatsEventList* data) {
|
||||
android::surfaceflinger::SurfaceflingerStatsLayerInfoWrapper atomList;
|
||||
if (!atomList.ParseFromString(protoData)) {
|
||||
ALOGW("Error parsing surface flinger layer stats to proto");
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
|
||||
for (const auto& atom : atomList.atom()) {
|
||||
// The strings must outlive the BytesFields, which only have a pointer to the data.
|
||||
std::string present2PresentStr, post2presentStr, acquire2PresentStr, latch2PresentStr,
|
||||
desired2PresentStr, post2AcquireStr, frameRateVoteStr, appDeadlineMissesStr;
|
||||
optional<BytesField> present2Present =
|
||||
getBytes(atom.present_to_present(), present2PresentStr);
|
||||
optional<BytesField> post2present = getBytes(atom.post_to_present(), post2presentStr);
|
||||
optional<BytesField> acquire2Present =
|
||||
getBytes(atom.acquire_to_present(), acquire2PresentStr);
|
||||
optional<BytesField> latch2Present = getBytes(atom.latch_to_present(), latch2PresentStr);
|
||||
optional<BytesField> desired2Present =
|
||||
getBytes(atom.desired_to_present(), desired2PresentStr);
|
||||
optional<BytesField> post2Acquire = getBytes(atom.post_to_acquire(), post2AcquireStr);
|
||||
optional<BytesField> frameRateVote = getBytes(atom.set_frame_rate_vote(), frameRateVoteStr);
|
||||
optional<BytesField> appDeadlineMisses =
|
||||
getBytes(atom.app_deadline_misses(), appDeadlineMissesStr);
|
||||
|
||||
// Fail if any serialization to bytes failed.
|
||||
if (!present2Present || !post2present || !acquire2Present || !latch2Present ||
|
||||
!desired2Present || !post2Acquire || !frameRateVote || !appDeadlineMisses) {
|
||||
return AStatsManager_PULL_SKIP;
|
||||
}
|
||||
|
||||
android::util::addAStatsEvent(data, android::util::SURFACEFLINGER_STATS_LAYER_INFO,
|
||||
atom.layer_name().c_str(), atom.total_frames(),
|
||||
atom.dropped_frames(), present2Present.value(),
|
||||
post2present.value(), acquire2Present.value(),
|
||||
latch2Present.value(), desired2Present.value(),
|
||||
post2Acquire.value(), atom.late_acquire_frames(),
|
||||
atom.bad_desired_present_frames(), atom.uid(),
|
||||
atom.total_timeline_frames(), atom.total_janky_frames(),
|
||||
atom.total_janky_frames_with_long_cpu(),
|
||||
atom.total_janky_frames_with_long_gpu(),
|
||||
atom.total_janky_frames_sf_unattributed(),
|
||||
atom.total_janky_frames_app_unattributed(),
|
||||
atom.total_janky_frames_sf_scheduling(),
|
||||
atom.total_jank_frames_sf_prediction_error(),
|
||||
atom.total_jank_frames_app_buffer_stuffing(),
|
||||
atom.display_refresh_rate_bucket(), atom.render_rate_bucket(),
|
||||
frameRateVote.value(), appDeadlineMisses.value());
|
||||
}
|
||||
return AStatsManager_PULL_SUCCESS;
|
||||
}
|
||||
|
||||
} // namespace stats
|
||||
} // namespace server
|
||||
} // namespace android
|
||||
44
services/core/jni/stats/SurfaceFlingerPuller.h
Normal file
44
services/core/jni/stats/SurfaceFlingerPuller.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2021 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.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stats_event.h>
|
||||
#include <stats_pull_atom_callback.h>
|
||||
#include <utils/String16.h>
|
||||
|
||||
namespace android {
|
||||
namespace server {
|
||||
namespace stats {
|
||||
|
||||
/**
|
||||
* Pulls data from surfaceflinger.
|
||||
* The indirection is needed because surfaceflinger is a bootstrap process.
|
||||
*/
|
||||
class SurfaceFlingerPuller {
|
||||
public:
|
||||
AStatsManager_PullAtomCallbackReturn pull(int32_t atomTag, AStatsEventList* data);
|
||||
|
||||
private:
|
||||
AStatsManager_PullAtomCallbackReturn parseGlobalInfoPull(const std::string& protoData,
|
||||
AStatsEventList* data);
|
||||
AStatsManager_PullAtomCallbackReturn parseLayerInfoPull(const std::string& protoData,
|
||||
AStatsEventList* data);
|
||||
};
|
||||
|
||||
} // namespace stats
|
||||
} // namespace server
|
||||
} // namespace android
|
||||
Reference in New Issue
Block a user