Merge changes from topic "new-puller-migration"
* changes:
GpuStats: migrate to new statsd native puller api (part 3)
GpuStats: migrate to new statsd native puller api (part 2)
GpuStats: migrate to new statsd native puller api (part 1)
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 0d943b7..6e5da52 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -15,12 +15,24 @@
*/
/**
- * @addtogroup ImageDecoder
+ * @defgroup ImageDecoder
+ *
+ * Functions for converting encoded images into RGBA pixels.
+ *
+ * Similar to the Java counterpart android.graphics.ImageDecoder, it can be used
+ * to decode images like PNG, JPEG, GIF, WEBP and HEIF. It has similar options
+ * for scaling, cropping, and choosing the output format. Unlike the Java API,
+ * which can create an android.graphics.Bitmap or
+ * android.graphics.drawable.Drawable object, AImageDecoder decodes directly
+ * into memory provided by the client. For more information, see the
+ * <a href="https://developer.android.com/ndk/guides/image-decoder">Image decoder</a>
+ * developer guide.
* @{
*/
/**
- * @file imageDecoder.h
+ * @file imagedecoder.h
+ * @brief API for decoding images.
*/
#ifndef ANDROID_IMAGE_DECODER_H
@@ -38,32 +50,54 @@
#if __ANDROID_API__ >= 30
-/** AImageDecoder functions result code. */
+/**
+ * {@link AImageDecoder} functions result code. Many functions will return one of these
+ * to indicate success ({@link ANDROID_IMAGE_DECODER_SUCCESS}) or the reason
+ * for the failure. On failure, any out-parameters should be considered
+ * uninitialized, except where specified.
+ */
enum {
- // Decoding was successful and complete.
+ /**
+ * Decoding was successful and complete.
+ */
ANDROID_IMAGE_DECODER_SUCCESS = 0,
- // The input was incomplete. In decodeImage, this means a partial
- // image was decoded. Undecoded lines are all zeroes.
- // In AImageDecoder_create*, no AImageDecoder was created.
+ /**
+ * The input was incomplete.
+ */
ANDROID_IMAGE_DECODER_INCOMPLETE = -1,
- // The input contained an error after decoding some lines. Similar to
- // INCOMPLETE, above.
+ /**
+ * The input contained an error after decoding some lines.
+ */
ANDROID_IMAGE_DECODER_ERROR = -2,
- // Could not convert, e.g. attempting to decode an image with
- // alpha to an opaque format.
+ /**
+ * Could not convert. For example, attempting to decode an image with
+ * alpha to an opaque format.
+ */
ANDROID_IMAGE_DECODER_INVALID_CONVERSION = -3,
- // The scale is invalid. It may have overflowed, or it may be incompatible
- // with the current alpha setting.
+ /**
+ * The scale is invalid. It may have overflowed, or it may be incompatible
+ * with the current alpha setting.
+ */
ANDROID_IMAGE_DECODER_INVALID_SCALE = -4,
- // Some other parameter was bad (e.g. pixels)
+ /**
+ * Some other parameter was bad.
+ */
ANDROID_IMAGE_DECODER_BAD_PARAMETER = -5,
- // Input was invalid i.e. broken before decoding any pixels.
+ /**
+ * Input was invalid before decoding any pixels.
+ */
ANDROID_IMAGE_DECODER_INVALID_INPUT = -6,
- // A seek was required, and failed.
+ /**
+ * A seek was required and it failed.
+ */
ANDROID_IMAGE_DECODER_SEEK_ERROR = -7,
- // Some other error (e.g. OOM)
+ /**
+ * Some other error. For example, an internal allocation failed.
+ */
ANDROID_IMAGE_DECODER_INTERNAL_ERROR = -8,
- // We did not recognize the format
+ /**
+ * AImageDecoder did not recognize the format.
+ */
ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9
};
@@ -76,36 +110,45 @@
* - {@link AImageDecoder_createFromAAsset}
* - {@link AImageDecoder_createFromFd}
* - {@link AImageDecoder_createFromBuffer}
+ *
+ * After creation, {@link AImageDecoder_getHeaderInfo} can be used to retrieve
+ * information about the encoded image. Other functions, like
+ * {@link AImageDecoder_setTargetSize}, can be used to specify how to decode, and
+ * {@link AImageDecoder_decode} will decode into client provided memory.
+ *
+ * {@link AImageDecoder} objects are NOT thread-safe, and should not be shared across
+ * threads.
*/
typedef struct AImageDecoder AImageDecoder;
/**
- * Create a new AImageDecoder from an AAsset.
+ * Create a new {@link AImageDecoder} from an {@link AAsset}.
*
* @param asset {@link AAsset} containing encoded image data. Client is still
- * responsible for calling {@link AAsset_close} on it.
+ * responsible for calling {@link AAsset_close} on it, which may be
+ * done after deleting the returned {@link AImageDecoder}.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
* a newly created {@link AImageDecoder}. Caller is
* responsible for calling {@link AImageDecoder_delete} on it.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
- * indicating reason for the failure.
+ * indicating the reason for the failure.
*/
int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder)
__INTRODUCED_IN(30);
/**
- * Create a new AImageDecoder from a file descriptor.
+ * Create a new {@link AImageDecoder} from a file descriptor.
*
* @param fd Seekable, readable, open file descriptor for encoded data.
* Client is still responsible for closing it, which may be done
- * *after* deleting the returned AImageDecoder.
+ * after deleting the returned {@link AImageDecoder}.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
* a newly created {@link AImageDecoder}. Caller is
* responsible for calling {@link AImageDecoder_delete} on it.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
- * indicating reason for the failure.
+ * indicating the reason for the failure.
*/
int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
@@ -113,7 +156,7 @@
* Create a new AImageDecoder from a buffer.
*
* @param buffer Pointer to encoded data. Must be valid for the entire time
- * the AImageDecoder is used.
+ * the {@link AImageDecoder} is used.
* @param length Byte length of buffer.
* @param outDecoder On success (i.e. return value is
* {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
@@ -136,7 +179,7 @@
* @param format {@link AndroidBitmapFormat} to use for the output.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} if the format is compatible
* with the image and {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}
- * otherwise. In the latter case, the AImageDecoder uses the
+ * otherwise. In the latter case, the {@link AImageDecoder} uses the
* format it was already planning to use (either its default
* or a previously successful setting from this function).
*/
@@ -146,23 +189,25 @@
/**
* Specify whether the output's pixels should be unpremultiplied.
*
- * By default, the decoder will premultiply the pixels, if they have alpha. Pass
- * false to this method to leave them unpremultiplied. This has no effect on an
+ * By default, {@link AImageDecoder_decodeImage} will premultiply the pixels, if they have alpha.
+ * Pass true to this method to leave them unpremultiplied. This has no effect on an
* opaque image.
*
- * @param required Pass true to leave the pixels unpremultiplied.
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ * @param unpremultipliedRequired Pass true to leave the pixels unpremultiplied.
+ * @return an enum describing whether the call succeeded.
+ * - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
* - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION} if the conversion
* is not possible
* - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad parameters
*/
-int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*, bool required) __INTRODUCED_IN(30);
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*,
+ bool unpremultipliedRequired) __INTRODUCED_IN(30);
/**
* Choose the dataspace for the output.
*
- * Not supported for {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
- * an ADataSpace.
+ * Ignored by {@link ANDROID_BITMAP_FORMAT_A_8}, which does not support
+ * an {@link ADataSpace}.
*
* @param dataspace The {@link ADataSpace} to decode into. An ADataSpace
* specifies how to interpret the colors. By default,
@@ -170,10 +215,10 @@
* {@link AImageDecoderHeaderInfo_getDataSpace}. If this
* parameter is set to a different ADataSpace, AImageDecoder
* will transform the output into the specified ADataSpace.
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
- * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null
- * AImageDecoder or an integer that does not correspond to an
- * ADataSpace value.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for a null
+ * {@link AImageDecoder} or an integer that does not correspond to an
+ * {@link ADataSpace} value.
*/
int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
@@ -191,10 +236,11 @@
* {@link AImageDecoder_getMinimumStride}, which will now return
* a value based on this width.
* @param height Height of the output (prior to cropping).
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
- * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
- * pointer is null, width or height is <= 0, or any existing crop is
- * not contained by the image dimensions.
+ * @return an enum describing whether the call succeeded.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the {@link AImageDecoder}
+ * pointer is null, width or height is <= 0, or any existing crop is
+ * not contained by the new image dimensions.
*/
int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) __INTRODUCED_IN(30);
@@ -213,10 +259,11 @@
* 1/2 of the original dimensions, with 1/4 the number of
* pixels.
* @param width Out parameter for the width sampled by sampleSize, and rounded
- * direction that the decoder can do most efficiently.
+ * in the direction that the decoder can do most efficiently.
* @param height Out parameter for the height sampled by sampleSize, and rounded
- * direction that the decoder can do most efficiently.
- * @return ANDROID_IMAGE_DECODER result code.
+ * in the direction that the decoder can do most efficiently.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad input.
*/
int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
int32_t* width, int32_t* height) __INTRODUCED_IN(30);
@@ -234,18 +281,21 @@
* value based on the width of the crop. An empty ARect -
* specifically { 0, 0, 0, 0 } - may be used to remove the cropping
* behavior. Any other empty or unsorted ARects will result in
- * returning ANDROID_IMAGE_DECODER_BAD_PARAMETER.
- * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
- * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
- * pointer is null or the crop is not contained by the image
- * dimensions.
+ * returning {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}.
+ * @return an enum describing whether the call succeeded.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or
+ * {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the {@link AImageDecoder}
+ * pointer is null or the crop is not contained by the image
+ * dimensions.
*/
int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
-/**
- * Opaque handle for reading header info.
- */
struct AImageDecoderHeaderInfo;
+/**
+ * Opaque handle for representing information about the encoded image. It can
+ * be passed to methods like {@link AImageDecoderHeaderInfo_getWidth} and
+ * {@link AImageDecoderHeaderInfo_getHeight}.
+ */
typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
/**
@@ -258,12 +308,16 @@
const AImageDecoder*) __INTRODUCED_IN(30);
/**
- * Report the native width of the encoded image.
+ * Report the native width of the encoded image. This is also the logical
+ * pixel width of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size.
*/
int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report the native height of the encoded image.
+ * Report the native height of the encoded image. This is also the logical
+ * pixel height of the output, unless {@link AImageDecoder_setTargetSize} is
+ * used to choose a different size.
*/
int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
@@ -277,7 +331,7 @@
/**
* Report the {@link AndroidBitmapFormat} the AImageDecoder will decode to
- * by default. AImageDecoder will try to choose one that is sensible
+ * by default. {@link AImageDecoder} will try to choose one that is sensible
* for the image and the system. Note that this does not indicate the
* encoded format of the image.
*/
@@ -285,18 +339,17 @@
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report how the AImageDecoder will handle alpha by default. If the image
+ * Report how the {@link AImageDecoder} will handle alpha by default. If the image
* contains no alpha (according to its header), this will return
* {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
- * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}.
- *
- * For animated images only the opacity of the first frame is reported.
+ * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}, because
+ * {@link AImageDecoder_decodeImage} will premultiply pixels by default.
*/
int AImageDecoderHeaderInfo_getAlphaFlags(
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Report the dataspace the AImageDecoder will decode to by default.
+ * Report the dataspace the {@link AImageDecoder} will decode to by default.
* AImageDecoder will try to choose one that is sensible for the
* image and the system. Note that this may not exactly match the ICC
* profile (or other color information) stored in the encoded image.
@@ -315,26 +368,35 @@
const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
/**
- * Return the minimum stride that can be used, taking the specified
- * (or default) (possibly scaled) width, crop rect and
- * {@link AndroidBitmapFormat} into account.
+ * Return the minimum stride that can be used in
+ * {@link AImageDecoder_decodeImage).
+ *
+ * This stride provides no padding, meaning it will be exactly equal to the
+ * width times the number of bytes per pixel for the {@link AndroidBitmapFormat}
+ * being used.
+ *
+ * If the output is scaled (via {@link AImageDecoder_setTargetSize}) and/or
+ * cropped (via {@link AImageDecoder_setCrop}), this takes those into account.
*/
size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
/**
- * Decode the image into pixels, using the settings of the AImageDecoder.
+ * Decode the image into pixels, using the settings of the {@link AImageDecoder}.
*
* @param decoder Opaque object representing the decoder.
* @param pixels On success, will be filled with the result
- * of the decode. Must be large enough to fit |size| bytes.
+ * of the decode. Must be large enough to hold |size| bytes.
* @param stride Width in bytes of a single row. Must be at least
- * {@link AImageDecoder_getMinimumStride}.
+ * {@link AImageDecoder_getMinimumStride} and a multiple of the
+ * bytes per pixel of the {@link AndroidBitmapFormat}.
* @param size Size of the pixel buffer in bytes. Must be at least
* stride * (height - 1) +
- * {@link AImageDecoder_getMinimumStride}. Must also be a multiple
- * of the bytes per pixel of the {@link AndroidBitmapFormat}.
+ * {@link AImageDecoder_getMinimumStride}.
* @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success, or an error code
* from the same enum describing the failure.
+ * {@link ANDROID_IMAGE_DECODER_INCOMPLETE} or
+ * {@link ANDROID_IMAGE_DECODER_ERROR} means that a partial image was
+ * decoded, and undecoded lines have been initialized to all zeroes.
*/
int AImageDecoder_decodeImage(AImageDecoder* decoder,
void* pixels, size_t stride,
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index a7a7292..618f88c 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -87,4 +87,7 @@
* package.
*/
@utf8InCpp String getModuleMetadataPackageName();
+
+ /* Returns the names of all packages. */
+ @utf8InCpp String[] getAllPackages();
}
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 4e62da7..e2f5d31 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -31,6 +31,68 @@
namespace android {
+void BLASTBufferItemConsumer::onDisconnect() {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = false;
+ if (mPreviouslyConnected) {
+ mDisconnectEvents.push(mCurrentFrameNumber);
+ }
+ mFrameEventHistory.onDisconnect();
+}
+
+void BLASTBufferItemConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ if (newTimestamps) {
+ // BufferQueueProducer only adds a new timestamp on
+ // queueBuffer
+ mCurrentFrameNumber = newTimestamps->frameNumber;
+ mFrameEventHistory.addQueue(*newTimestamps);
+ }
+ if (outDelta) {
+ // frame event histories will be processed
+ // only after the producer connects and requests
+ // deltas for the first time. Forward this intent
+ // to SF-side to turn event processing back on
+ mPreviouslyConnected = mCurrentlyConnected;
+ mCurrentlyConnected = true;
+ mFrameEventHistory.getAndResetDelta(outDelta);
+ }
+}
+
+void BLASTBufferItemConsumer::updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
+ const sp<Fence>& glDoneFence,
+ const sp<Fence>& presentFence,
+ const sp<Fence>& prevReleaseFence,
+ CompositorTiming compositorTiming,
+ nsecs_t latchTime, nsecs_t dequeueReadyTime) {
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+
+ // if the producer is not connected, don't bother updating,
+ // the next producer that connects won't access this frame event
+ if (!mCurrentlyConnected) return;
+ std::shared_ptr<FenceTime> glDoneFenceTime = std::make_shared<FenceTime>(glDoneFence);
+ std::shared_ptr<FenceTime> presentFenceTime = std::make_shared<FenceTime>(presentFence);
+ std::shared_ptr<FenceTime> releaseFenceTime = std::make_shared<FenceTime>(prevReleaseFence);
+
+ mFrameEventHistory.addLatch(frameNumber, latchTime);
+ mFrameEventHistory.addRelease(frameNumber, dequeueReadyTime, std::move(releaseFenceTime));
+ mFrameEventHistory.addPreComposition(frameNumber, refreshStartTime);
+ mFrameEventHistory.addPostComposition(frameNumber, glDoneFenceTime, presentFenceTime,
+ compositorTiming);
+}
+
+void BLASTBufferItemConsumer::getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect) {
+ bool disconnect = false;
+ Mutex::Autolock lock(mFrameEventHistoryMutex);
+ while (!mDisconnectEvents.empty() && mDisconnectEvents.front() <= frameNumber) {
+ disconnect = true;
+ mDisconnectEvents.pop();
+ }
+ if (needsDisconnect != nullptr) *needsDisconnect = disconnect;
+}
+
BLASTBufferQueue::BLASTBufferQueue(const sp<SurfaceControl>& surface, int width, int height)
: mSurfaceControl(surface),
mWidth(width),
@@ -39,7 +101,7 @@
BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
mBufferItemConsumer =
- new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
+ new BLASTBufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
static int32_t id = 0;
auto name = std::string("BLAST Consumer") + std::to_string(id);
id++;
@@ -79,11 +141,21 @@
std::unique_lock _lock{mMutex};
ATRACE_CALL();
+ if (!stats.empty()) {
+ mTransformHint = stats[0].transformHint;
+ mBufferItemConsumer->setTransformHint(mTransformHint);
+ mBufferItemConsumer->updateFrameTimestamps(stats[0].frameEventStats.frameNumber,
+ stats[0].frameEventStats.refreshStartTime,
+ stats[0].frameEventStats.gpuCompositionDoneFence,
+ stats[0].presentFence,
+ stats[0].previousReleaseFence,
+ stats[0].frameEventStats.compositorTiming,
+ stats[0].latchTime,
+ stats[0].frameEventStats.dequeueReadyTime);
+ }
if (mPendingReleaseItem.item.mGraphicBuffer != nullptr) {
- if (stats.size() > 0) {
+ if (!stats.empty()) {
mPendingReleaseItem.releaseFence = stats[0].previousReleaseFence;
- mTransformHint = stats[0].transformHint;
- mBufferItemConsumer->setTransformHint(mTransformHint);
} else {
ALOGE("Warning: no SurfaceControlStats returned in BLASTBufferQueue callback");
mPendingReleaseItem.releaseFence = nullptr;
@@ -144,6 +216,14 @@
mNumAcquired++;
mSubmitted.push(bufferItem);
+ bool needsDisconnect = false;
+ mBufferItemConsumer->getConnectionEvents(bufferItem.mFrameNumber, &needsDisconnect);
+
+ // if producer disconnected before, notify SurfaceFlinger
+ if (needsDisconnect) {
+ t->notifyProducerDisconnect(mSurfaceControl);
+ }
+
// Ensure BLASTBufferQueue stays alive until we receive the transaction complete callback.
incStrong((void*)transactionCallbackThunk);
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index e5e25aa..69f7894 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -30,6 +30,66 @@
} // Anonymous namespace
+status_t FrameEventHistoryStats::writeToParcel(Parcel* output) const {
+ status_t err = output->writeUint64(frameNumber);
+ if (err != NO_ERROR) return err;
+
+ if (gpuCompositionDoneFence) {
+ err = output->writeBool(true);
+ if (err != NO_ERROR) return err;
+
+ err = output->write(*gpuCompositionDoneFence);
+ } else {
+ err = output->writeBool(false);
+ }
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.deadline);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.interval);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(compositorTiming.presentLatency);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = output->writeInt64(dequeueReadyTime);
+ return err;
+}
+
+status_t FrameEventHistoryStats::readFromParcel(const Parcel* input) {
+ status_t err = input->readUint64(&frameNumber);
+ if (err != NO_ERROR) return err;
+
+ bool hasFence = false;
+ err = input->readBool(&hasFence);
+ if (err != NO_ERROR) return err;
+
+ if (hasFence) {
+ gpuCompositionDoneFence = new Fence();
+ err = input->read(*gpuCompositionDoneFence);
+ if (err != NO_ERROR) return err;
+ }
+
+ err = input->readInt64(&(compositorTiming.deadline));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.interval));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&(compositorTiming.presentLatency));
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&refreshStartTime);
+ if (err != NO_ERROR) return err;
+
+ err = input->readInt64(&dequeueReadyTime);
+ return err;
+}
+
status_t SurfaceStats::writeToParcel(Parcel* output) const {
status_t err = output->writeStrongBinder(surfaceControl);
if (err != NO_ERROR) {
@@ -49,6 +109,11 @@
err = output->writeBool(false);
}
err = output->writeUint32(transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = output->writeParcelable(eventStats);
return err;
}
@@ -74,6 +139,11 @@
}
}
err = input->readUint32(&transformHint);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ err = input->readParcelable(&eventStats);
return err;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 43bccf6..7017b7c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -222,8 +222,10 @@
surfaceControlStats
.emplace_back(callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl],
- surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
- surfaceStats.transformHint);
+ transactionStats.latchTime, surfaceStats.acquireTime,
+ transactionStats.presentFence,
+ surfaceStats.previousReleaseFence, surfaceStats.transformHint,
+ surfaceStats.eventStats);
if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
callbacksMap[callbackId]
.surfaceControls[surfaceStats.surfaceControl]
@@ -1235,6 +1237,18 @@
return *this;
}
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::notifyProducerDisconnect(
+ const sp<SurfaceControl>& sc) {
+ layer_state_t* s = getLayerState(sc);
+ if (!s) {
+ mStatus = BAD_INDEX;
+ return *this;
+ }
+
+ s->what |= layer_state_t::eProducerDisconnect;
+ return *this;
+}
+
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::detachChildren(
const sp<SurfaceControl>& sc) {
layer_state_t* s = getLayerState(sc);
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index be429fe..d72eb5a 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -33,6 +33,35 @@
class BufferItemConsumer;
+class BLASTBufferItemConsumer : public BufferItemConsumer {
+public:
+ BLASTBufferItemConsumer(const sp<IGraphicBufferConsumer>& consumer, uint64_t consumerUsage,
+ int bufferCount, bool controlledByApp)
+ : BufferItemConsumer(consumer, consumerUsage, bufferCount, controlledByApp),
+ mCurrentlyConnected(false),
+ mPreviouslyConnected(false) {}
+
+ void onDisconnect() override;
+ void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+ FrameEventHistoryDelta* outDelta) override
+ REQUIRES(mFrameEventHistoryMutex);
+ void updateFrameTimestamps(uint64_t frameNumber, nsecs_t refreshStartTime,
+ const sp<Fence>& gpuCompositionDoneFence,
+ const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
+ CompositorTiming compositorTiming, nsecs_t latchTime,
+ nsecs_t dequeueReadyTime) REQUIRES(mFrameEventHistoryMutex);
+ void getConnectionEvents(uint64_t frameNumber, bool* needsDisconnect);
+
+private:
+ uint64_t mCurrentFrameNumber = 0;
+
+ Mutex mFrameEventHistoryMutex;
+ ConsumerFrameEventHistory mFrameEventHistory GUARDED_BY(mFrameEventHistoryMutex);
+ std::queue<uint64_t> mDisconnectEvents GUARDED_BY(mFrameEventHistoryMutex);
+ bool mCurrentlyConnected GUARDED_BY(mFrameEventHistoryMutex);
+ bool mPreviouslyConnected GUARDED_BY(mFrameEventHistoryMutex);
+};
+
class BLASTBufferQueue
: public ConsumerBase::FrameAvailableListener, public BufferItemConsumer::BufferFreedListener
{
@@ -89,7 +118,7 @@
sp<IGraphicBufferConsumer> mConsumer;
sp<IGraphicBufferProducer> mProducer;
- sp<BufferItemConsumer> mBufferItemConsumer;
+ sp<BLASTBufferItemConsumer> mBufferItemConsumer;
SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
};
diff --git a/libs/gui/include/gui/FrameTimestamps.h b/libs/gui/include/gui/FrameTimestamps.h
index 816dd2b..4af8659 100644
--- a/libs/gui/include/gui/FrameTimestamps.h
+++ b/libs/gui/include/gui/FrameTimestamps.h
@@ -174,7 +174,6 @@
std::shared_ptr<FenceTime> acquireFence{FenceTime::NO_FENCE};
};
-
// Used by the consumer to keep track of which fields it already sent to
// the producer.
class FrameEventDirtyFields {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 9c15225..c58634b 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -21,6 +21,7 @@
#include <binder/Parcelable.h>
#include <binder/SafeInterface.h>
+#include <gui/FrameTimestamps.h>
#include <ui/Fence.h>
#include <utils/Timers.h>
@@ -35,6 +36,27 @@
using CallbackId = int64_t;
+class FrameEventHistoryStats : public Parcelable {
+public:
+ status_t writeToParcel(Parcel* output) const override;
+ status_t readFromParcel(const Parcel* input) override;
+
+ FrameEventHistoryStats() = default;
+ FrameEventHistoryStats(uint64_t fn, const sp<Fence>& gpuCompFence, CompositorTiming compTiming,
+ nsecs_t refreshTime, nsecs_t dequeueReadyTime)
+ : frameNumber(fn),
+ gpuCompositionDoneFence(gpuCompFence),
+ compositorTiming(compTiming),
+ refreshStartTime(refreshTime),
+ dequeueReadyTime(dequeueReadyTime) {}
+
+ uint64_t frameNumber;
+ sp<Fence> gpuCompositionDoneFence;
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime;
+ nsecs_t dequeueReadyTime;
+};
+
class SurfaceStats : public Parcelable {
public:
status_t writeToParcel(Parcel* output) const override;
@@ -42,16 +64,18 @@
SurfaceStats() = default;
SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
- uint32_t hint)
+ uint32_t hint, FrameEventHistoryStats frameEventStats)
: surfaceControl(sc),
acquireTime(time),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ eventStats(frameEventStats) {}
sp<IBinder> surfaceControl;
nsecs_t acquireTime = -1;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats eventStats;
};
class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c256a09..2d53b48 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -102,6 +102,7 @@
eFrameRateSelectionPriority = 0x20'00000000,
eFrameRateChanged = 0x40'00000000,
eBackgroundBlurRadiusChanged = 0x80'00000000,
+ eProducerDisconnect = 0x100'00000000,
};
layer_state_t()
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 6eec2b7..d0bb6a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -52,17 +52,24 @@
class Region;
struct SurfaceControlStats {
- SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t time,
- const sp<Fence>& prevReleaseFence, uint32_t hint)
+ SurfaceControlStats(const sp<SurfaceControl>& sc, nsecs_t latchTime, nsecs_t acquireTime,
+ const sp<Fence>& presentFence, const sp<Fence>& prevReleaseFence,
+ uint32_t hint, FrameEventHistoryStats eventStats)
: surfaceControl(sc),
- acquireTime(time),
+ latchTime(latchTime),
+ acquireTime(acquireTime),
+ presentFence(presentFence),
previousReleaseFence(prevReleaseFence),
- transformHint(hint) {}
+ transformHint(hint),
+ frameEventStats(eventStats) {}
sp<SurfaceControl> surfaceControl;
+ nsecs_t latchTime = -1;
nsecs_t acquireTime = -1;
+ sp<Fence> presentFence;
sp<Fence> previousReleaseFence;
uint32_t transformHint = 0;
+ FrameEventHistoryStats frameEventStats;
};
using TransactionCompletedCallbackTakesContext =
@@ -484,6 +491,9 @@
Transaction& addTransactionCompletedCallback(
TransactionCompletedCallbackTakesContext callback, void* callbackContext);
+ // ONLY FOR BLAST ADAPTER
+ Transaction& notifyProducerDisconnect(const sp<SurfaceControl>& sc);
+
// Detaches all child surfaces (and their children recursively)
// from their SurfaceControl.
// The child SurfaceControls will not throw exceptions or return errors,
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index a273914..b40eb14 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -21,6 +21,7 @@
#include <android/hardware/graphics/common/1.2/types.h>
#include <gui/BufferQueueCore.h>
#include <gui/BufferQueueProducer.h>
+#include <gui/FrameTimestamps.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
#include <gui/SurfaceComposerClient.h>
@@ -647,4 +648,79 @@
TEST_F(BLASTBufferQueueTransformTest, setTransform_ROT_270) {
test(ui::Transform::ROT_270);
}
+
+class BLASTFrameEventHistoryTest : public BLASTBufferQueueTest {
+public:
+ void setUpAndQueueBuffer(const sp<IGraphicBufferProducer>& igbProducer,
+ nsecs_t* requestedPresentTime, nsecs_t* postedTime,
+ IGraphicBufferProducer::QueueBufferOutput* qbOutput,
+ bool getFrameTimestamps) {
+ int slot;
+ sp<Fence> fence;
+ sp<GraphicBuffer> buf;
+ auto ret = igbProducer->dequeueBuffer(&slot, &fence, mDisplayWidth, mDisplayHeight,
+ PIXEL_FORMAT_RGBA_8888, GRALLOC_USAGE_SW_WRITE_OFTEN,
+ nullptr, nullptr);
+ ASSERT_EQ(IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION, ret);
+ ASSERT_EQ(OK, igbProducer->requestBuffer(slot, &buf));
+
+ nsecs_t requestedTime = systemTime();
+ if (requestedPresentTime) *requestedPresentTime = requestedTime;
+ IGraphicBufferProducer::QueueBufferInput input(requestedTime, false, HAL_DATASPACE_UNKNOWN,
+ Rect(mDisplayWidth, mDisplayHeight),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
+ Fence::NO_FENCE, /*sticky*/ 0,
+ getFrameTimestamps);
+ if (postedTime) *postedTime = systemTime();
+ igbProducer->queueBuffer(slot, input, qbOutput);
+ }
+};
+
+TEST_F(BLASTFrameEventHistoryTest, FrameEventHistory_Basic) {
+ BLASTBufferQueueHelper adapter(mSurfaceControl, mDisplayWidth, mDisplayHeight);
+ sp<IGraphicBufferProducer> igbProducer;
+ ProducerFrameEventHistory history;
+ setUpProducer(adapter, igbProducer);
+
+ IGraphicBufferProducer::QueueBufferOutput qbOutput;
+ nsecs_t requestedPresentTimeA = 0;
+ nsecs_t postedTimeA = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeA, &postedTimeA, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+
+ FrameEvents* events = nullptr;
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ adapter.waitForCallbacks();
+
+ // queue another buffer so we query for frame event deltas
+ nsecs_t requestedPresentTimeB = 0;
+ nsecs_t postedTimeB = 0;
+ setUpAndQueueBuffer(igbProducer, &requestedPresentTimeB, &postedTimeB, &qbOutput, true);
+ history.applyDelta(qbOutput.frameTimestamps);
+ events = history.getFrame(1);
+ ASSERT_NE(nullptr, events);
+
+ // frame number, requestedPresentTime, and postTime should not have changed
+ ASSERT_EQ(1, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeA, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeA);
+
+ ASSERT_GE(events->latchTime, postedTimeA);
+ ASSERT_GE(events->dequeueReadyTime, events->latchTime);
+ ASSERT_NE(nullptr, events->gpuCompositionDoneFence);
+ ASSERT_NE(nullptr, events->displayPresentFence);
+ ASSERT_NE(nullptr, events->releaseFence);
+
+ // we should also have gotten the initial values for the next frame
+ events = history.getFrame(2);
+ ASSERT_NE(nullptr, events);
+ ASSERT_EQ(2, events->frameNumber);
+ ASSERT_EQ(requestedPresentTimeB, events->requestedPresentTime);
+ ASSERT_GE(events->postedTime, postedTimeB);
+}
} // namespace android
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 208a627..b3e34d5 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -25,22 +25,11 @@
#include <mutex>
#include <vector>
-#include <unordered_map>
namespace android {
class GpuStats;
-struct MemoryStruct {
- int64_t gpuMemory;
- int64_t mappedMemory;
- int64_t ionMemory;
-};
-
-// A map that keeps track of how much memory of each type is allocated by every process.
-// Format: map[pid][memoryType] = MemoryStruct()'
-using GpuMemoryMap = std::unordered_map<int32_t, std::unordered_map<std::string, MemoryStruct>>;
-
class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -80,8 +69,6 @@
status_t doDump(int fd, const Vector<String16>& args, bool asProto);
- status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const;
-
/*
* Attributes
*/
diff --git a/services/sensorservice/Android.bp b/services/sensorservice/Android.bp
index 1c9a4af..5246c78 100644
--- a/services/sensorservice/Android.bp
+++ b/services/sensorservice/Android.bp
@@ -42,6 +42,7 @@
"libbinder",
"libsensor",
"libsensorprivacy",
+ "libprotoutil",
"libcrypto",
"libbase",
"libhidlbase",
@@ -52,6 +53,8 @@
static_libs: ["android.hardware.sensors@1.0-convert"],
+ generated_headers: ["framework-cppstream-protos"],
+
// our public headers depend on libsensor and libsensorprivacy
export_shared_lib_headers: ["libsensor", "libsensorprivacy"],
}
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index 207b097..d7ca6e1 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -17,6 +17,8 @@
#include "RecentEventLogger.h"
#include "SensorServiceUtils.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <utils/Timers.h>
#include <inttypes.h>
@@ -84,6 +86,40 @@
return std::string(buffer.string());
}
+/**
+ * Dump debugging information as android.service.SensorEventsProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void RecentEventLogger::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorEventsProto;
+ std::lock_guard<std::mutex> lk(mLock);
+
+ proto->write(RecentEventsLog::RECENT_EVENTS_COUNT, int(mRecentEvents.size()));
+ for (int i = mRecentEvents.size() - 1; i >= 0; --i) {
+ const auto& ev = mRecentEvents[i];
+ const uint64_t token = proto->start(RecentEventsLog::EVENTS);
+ proto->write(Event::TIMESTAMP_SEC, float(ev.mEvent.timestamp) / 1e9f);
+ proto->write(Event::WALL_TIMESTAMP_MS, ev.mWallTime.tv_sec * 1000LL
+ + ns2ms(ev.mWallTime.tv_nsec));
+
+ if (mMaskData) {
+ proto->write(Event::MASKED, true);
+ } else {
+ if (mSensorType == SENSOR_TYPE_STEP_COUNTER) {
+ proto->write(Event::INT64_DATA, int64_t(ev.mEvent.u64.step_counter));
+ } else {
+ for (size_t k = 0; k < mEventSize; ++k) {
+ proto->write(Event::FLOAT_ARRAY, ev.mEvent.data[k]);
+ }
+ }
+ }
+ proto->end(token);
+ }
+}
+
void RecentEventLogger::setFormat(std::string format) {
if (format == "mask_data" ) {
mMaskData = true;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index 67378b7..3a2ae77 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -48,6 +48,7 @@
// Dumpable interface
virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
virtual void setFormat(std::string format) override;
protected:
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index c7a8f5b..33f940f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -21,6 +21,8 @@
#include "SensorService.h"
#include <android-base/logging.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <sensors/convert.h>
#include <cutils/atomic.h>
#include <utils/Errors.h>
@@ -39,6 +41,7 @@
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::SensorDeviceUtils::HidlServiceRegistrationWaiter;
+using android::util::ProtoOutputStream;
namespace android {
// ---------------------------------------------------------------------------
@@ -396,6 +399,43 @@
return result.string();
}
+/**
+ * Dump debugging information as android.service.SensorDeviceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorDevice::dump(ProtoOutputStream* proto) const {
+ using namespace service::SensorDeviceProto;
+ if (mSensors == nullptr) {
+ proto->write(INITIALIZED , false);
+ return;
+ }
+ proto->write(INITIALIZED , true);
+ proto->write(TOTAL_SENSORS , int(mSensorList.size()));
+ proto->write(ACTIVE_SENSORS , int(mActivationCount.size()));
+
+ Mutex::Autolock _l(mLock);
+ for (const auto & s : mSensorList) {
+ int32_t handle = s.handle;
+ const Info& info = mActivationCount.valueFor(handle);
+ if (info.numActiveClients() == 0) continue;
+
+ uint64_t token = proto->start(SENSORS);
+ proto->write(SensorProto::HANDLE , handle);
+ proto->write(SensorProto::ACTIVE_COUNT , int(info.batchParams.size()));
+ for (size_t j = 0; j < info.batchParams.size(); j++) {
+ const BatchParams& params = info.batchParams[j];
+ proto->write(SensorProto::SAMPLING_PERIOD_MS , params.mTSample / 1e6f);
+ proto->write(SensorProto::BATCHING_PERIOD_MS , params.mTBatch / 1e6f);
+ }
+ proto->write(SensorProto::SAMPLING_PERIOD_SELECTED , info.bestBatchParams.mTSample / 1e6f);
+ proto->write(SensorProto::BATCHING_PERIOD_SELECTED , info.bestBatchParams.mTBatch / 1e6f);
+ proto->end(token);
+ }
+}
+
ssize_t SensorDevice::getSensorList(sensor_t const** list) {
*list = &mSensorList[0];
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index d2c6994..33aa7d6 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -123,7 +123,8 @@
bool isSensorActive(int handle) const;
// Dumpable
- virtual std::string dump() const;
+ virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
private:
friend class Singleton<SensorDevice>;
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index cd0ea5d..106efd6 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -16,12 +16,16 @@
#include "SensorDevice.h"
#include "SensorDirectConnection.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#define UNUSED(x) (void)(x)
namespace android {
+using util::ProtoOutputStream;
+
SensorService::SensorDirectConnection::SensorDirectConnection(const sp<SensorService>& service,
uid_t uid, const sensors_direct_mem_t *mem, int32_t halChannelHandle,
const String16& opPackageName)
@@ -64,6 +68,27 @@
}
}
+/**
+ * Dump debugging information as android.service.SensorDirectConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorDirectConnection::dump(ProtoOutputStream* proto) const {
+ using namespace service::SensorDirectConnectionProto;
+ Mutex::Autolock _l(mConnectionLock);
+ proto->write(PACKAGE_NAME, std::string(String8(mOpPackageName).string()));
+ proto->write(HAL_CHANNEL_HANDLE, getHalChannelHandle());
+ proto->write(NUM_SENSOR_ACTIVATED, int(mActivated.size()));
+ for (auto &i : mActivated) {
+ uint64_t token = proto->start(SENSORS);
+ proto->write(SensorProto::SENSOR, i.first);
+ proto->write(SensorProto::RATE, i.second);
+ proto->end(token);
+ }
+}
+
sp<BitTube> SensorService::SensorDirectConnection::getSensorChannel() const {
return nullptr;
}
diff --git a/services/sensorservice/SensorDirectConnection.h b/services/sensorservice/SensorDirectConnection.h
index 5c398a8..ead08d3 100644
--- a/services/sensorservice/SensorDirectConnection.h
+++ b/services/sensorservice/SensorDirectConnection.h
@@ -40,6 +40,7 @@
const sensors_direct_mem_t *mem, int32_t halChannelHandle,
const String16& opPackageName);
void dump(String8& result) const;
+ void dump(util::ProtoOutputStream* proto) const;
uid_t getUid() const { return mUid; }
int32_t getHalChannelHandle() const;
bool isEquivalent(const sensors_direct_mem_t *mem) const;
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 0e40940..9a13c00 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -17,6 +17,8 @@
#include <sys/socket.h>
#include <utils/threads.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <sensor/SensorEventQueue.h>
#include "vec.h"
@@ -110,6 +112,51 @@
#endif
}
+/**
+ * Dump debugging information as android.service.SensorEventConnectionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorService::SensorEventConnection::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorEventConnectionProto;
+ Mutex::Autolock _l(mConnectionLock);
+
+ if (!mService->isWhiteListedPackage(getPackageName())) {
+ proto->write(OPERATING_MODE, OP_MODE_RESTRICTED);
+ } else if (mDataInjectionMode) {
+ proto->write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+ } else {
+ proto->write(OPERATING_MODE, OP_MODE_NORMAL);
+ }
+ proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(WAKE_LOCK_REF_COUNT, int32_t(mWakeLockRefCount));
+ proto->write(UID, int32_t(mUid));
+ proto->write(CACHE_SIZE, int32_t(mCacheSize));
+ proto->write(MAX_CACHE_SIZE, int32_t(mMaxCacheSize));
+ for (size_t i = 0; i < mSensorInfo.size(); ++i) {
+ const FlushInfo& flushInfo = mSensorInfo.valueAt(i);
+ const uint64_t token = proto->start(FLUSH_INFOS);
+ proto->write(FlushInfoProto::SENSOR_NAME,
+ std::string(mService->getSensorName(mSensorInfo.keyAt(i))));
+ proto->write(FlushInfoProto::SENSOR_HANDLE, mSensorInfo.keyAt(i));
+ proto->write(FlushInfoProto::FIRST_FLUSH_PENDING, flushInfo.mFirstFlushPending);
+ proto->write(FlushInfoProto::PENDING_FLUSH_EVENTS_TO_SEND,
+ flushInfo.mPendingFlushEventsToSend);
+ proto->end(token);
+ }
+#if DEBUG_CONNECTIONS
+ proto->write(EVENTS_RECEIVED, mEventsReceived);
+ proto->write(EVENTS_SENT, mEventsSent);
+ proto->write(EVENTS_CACHE, mEventsSentFromCache);
+ proto->write(EVENTS_DROPPED, mEventsReceived - (mEventsSentFromCache + mEventsSent +
+ mCacheSize));
+ proto->write(TOTAL_ACKS_NEEDED, mTotalAcksNeeded);
+ proto->write(TOTAL_ACKS_RECEIVED, mTotalAcksReceived);
+#endif
+}
+
bool SensorService::SensorEventConnection::addSensor(int32_t handle) {
Mutex::Autolock _l(mConnectionLock);
sp<SensorInterface> si = mService->getSensorInterfaceFromHandle(handle);
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index fd881cb..caf5d7c 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -62,6 +62,7 @@
bool removeSensor(int32_t handle);
void setFirstFlushPending(int32_t handle, bool value);
void dump(String8& result);
+ void dump(util::ProtoOutputStream* proto) const;
bool needsWakeLock();
void resetWakeLockRefCount();
String8 getPackageName() const;
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 414f673..e27b52b 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -18,6 +18,9 @@
#include "SensorFusion.h"
#include "SensorService.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+
namespace android {
// ---------------------------------------------------------------------------
@@ -183,7 +186,7 @@
return mAcc.getMinDelay();
}
-void SensorFusion::dump(String8& result) {
+void SensorFusion::dump(String8& result) const {
const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
"q=< %g, %g, %g, %g > (%g), "
@@ -235,5 +238,42 @@
fusion_nogyro.getBias().z);
}
+void SensorFusion::dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const {
+ using namespace service::SensorFusionProto::FusionProto;
+ const Fusion& fusion(mFusions[mode]);
+ proto->write(ENABLED, mEnabled[mode]);
+ proto->write(NUM_CLIENTS, (int)mClients[mode].size());
+ proto->write(ESTIMATED_GYRO_RATE, mEstimatedGyroRate);
+ proto->write(ATTITUDE_X, fusion.getAttitude().x);
+ proto->write(ATTITUDE_Y, fusion.getAttitude().y);
+ proto->write(ATTITUDE_Z, fusion.getAttitude().z);
+ proto->write(ATTITUDE_W, fusion.getAttitude().w);
+ proto->write(ATTITUDE_LENGTH, length(fusion.getAttitude()));
+ proto->write(BIAS_X, fusion.getBias().x);
+ proto->write(BIAS_Y, fusion.getBias().y);
+ proto->write(BIAS_Z, fusion.getBias().z);
+}
+
+/**
+ * Dump debugging information as android.service.SensorFusionProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorFusion::dump(util::ProtoOutputStream* proto) const {
+ uint64_t token = proto->start(service::SensorFusionProto::FUSION_9AXIS);
+ dumpFusion(FUSION_9AXIS, proto);
+ proto->end(token);
+
+ token = proto->start(service::SensorFusionProto::FUSION_NOMAG);
+ dumpFusion(FUSION_NOMAG, proto);
+ proto->end(token);
+
+ token = proto->start(service::SensorFusionProto::FUSION_NOGYRO);
+ dumpFusion(FUSION_NOGYRO, proto);
+ proto->end(token);
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index 8c0fbf9..66a7290 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -90,7 +90,9 @@
float getPowerUsage(int mode=FUSION_9AXIS) const;
int32_t getMinDelay() const;
- void dump(String8& result);
+ void dump(String8& result) const;
+ void dump(util::ProtoOutputStream* proto) const;
+ void dumpFusion(FUSION_MODE mode, util::ProtoOutputStream* proto) const;
};
diff --git a/services/sensorservice/SensorList.cpp b/services/sensorservice/SensorList.cpp
index aa306d8..0ce32cc 100644
--- a/services/sensorservice/SensorList.cpp
+++ b/services/sensorservice/SensorList.cpp
@@ -16,6 +16,8 @@
#include "SensorList.h"
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#include <utils/String8.h>
@@ -203,6 +205,64 @@
return std::string(result.string());
}
+/**
+ * Dump debugging information as android.service.SensorListProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+void SensorList::dump(util::ProtoOutputStream* proto) const {
+ using namespace service::SensorListProto;
+ using namespace service::SensorListProto::SensorProto;
+
+ forEachSensor([&proto] (const Sensor& s) -> bool {
+ const uint64_t token = proto->start(SENSORS);
+ proto->write(HANDLE, s.getHandle());
+ proto->write(NAME, std::string(s.getName().string()));
+ proto->write(VENDOR, std::string(s.getVendor().string()));
+ proto->write(VERSION, s.getVersion());
+ proto->write(STRING_TYPE, std::string(s.getStringType().string()));
+ proto->write(TYPE, s.getType());
+ proto->write(REQUIRED_PERMISSION, std::string(s.getRequiredPermission().size() ?
+ s.getRequiredPermission().string() : ""));
+ proto->write(FLAGS, int(s.getFlags()));
+ switch (s.getReportingMode()) {
+ case AREPORTING_MODE_CONTINUOUS:
+ proto->write(REPORTING_MODE, RM_CONTINUOUS);
+ break;
+ case AREPORTING_MODE_ON_CHANGE:
+ proto->write(REPORTING_MODE, RM_ON_CHANGE);
+ break;
+ case AREPORTING_MODE_ONE_SHOT:
+ proto->write(REPORTING_MODE, RM_ONE_SHOT);
+ break;
+ case AREPORTING_MODE_SPECIAL_TRIGGER:
+ proto->write(REPORTING_MODE, RM_SPECIAL_TRIGGER);
+ break;
+ default:
+ proto->write(REPORTING_MODE, RM_UNKNOWN);
+ }
+ proto->write(MAX_DELAY_US, s.getMaxDelay());
+ proto->write(MIN_DELAY_US, s.getMinDelay());
+ proto->write(FIFO_MAX_EVENT_COUNT, int(s.getFifoMaxEventCount()));
+ proto->write(FIFO_RESERVED_EVENT_COUNT, int(s.getFifoReservedEventCount()));
+ proto->write(IS_WAKEUP, s.isWakeUpSensor());
+ proto->write(DATA_INJECTION_SUPPORTED, s.isDataInjectionSupported());
+ proto->write(IS_DYNAMIC, s.isDynamicSensor());
+ proto->write(HAS_ADDITIONAL_INFO, s.hasAdditionalInfo());
+ proto->write(HIGHEST_RATE_LEVEL, s.getHighestDirectReportRateLevel());
+ proto->write(ASHMEM, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_ASHMEM));
+ proto->write(GRALLOC, s.isDirectChannelTypeSupported(SENSOR_DIRECT_MEM_TYPE_GRALLOC));
+ proto->write(MIN_VALUE, s.getMinValue());
+ proto->write(MAX_VALUE, s.getMaxValue());
+ proto->write(RESOLUTION, s.getResolution());
+ proto->write(POWER_USAGE, s.getPowerUsage());
+ proto->end(token);
+ return true;
+ });
+}
+
SensorList::~SensorList() {
}
diff --git a/services/sensorservice/SensorList.h b/services/sensorservice/SensorList.h
index 6b90ad9..8424b22 100644
--- a/services/sensorservice/SensorList.h
+++ b/services/sensorservice/SensorList.h
@@ -71,6 +71,7 @@
// Dumpable interface
virtual std::string dump() const override;
+ virtual void dump(util::ProtoOutputStream* proto) const override;
virtual ~SensorList();
private:
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index 5411515..a34a65b 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -17,10 +17,14 @@
#ifndef ANDROID_SENSOR_REGISTRATION_INFO_H
#define ANDROID_SENSOR_REGISTRATION_INFO_H
-#include "SensorServiceUtils.h"
-#include <utils/Thread.h>
+#include <ctime>
#include <iomanip>
#include <sstream>
+#include <utils/Thread.h>
+
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
+#include "SensorServiceUtils.h"
namespace android {
@@ -30,7 +34,7 @@
public:
SensorRegistrationInfo() : mPackageName() {
mSensorHandle = mSamplingRateUs = mMaxReportLatencyUs = INT32_MIN;
- mHour = mMin = mSec = INT8_MIN;
+ mRealtimeSec = 0;
mActivated = false;
}
@@ -47,25 +51,26 @@
mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
- time_t rawtime = time(nullptr);
- struct tm * timeinfo = localtime(&rawtime);
- mHour = static_cast<int8_t>(timeinfo->tm_hour);
- mMin = static_cast<int8_t>(timeinfo->tm_min);
- mSec = static_cast<int8_t>(timeinfo->tm_sec);
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME_COARSE, &curTime);
+ mRealtimeSec = curTime.tv_sec;
}
static bool isSentinel(const SensorRegistrationInfo& info) {
- return (info.mHour == INT8_MIN &&
- info.mMin == INT8_MIN &&
- info.mSec == INT8_MIN);
+ return (info.mSensorHandle == INT32_MIN && info.mRealtimeSec == 0);
}
// Dumpable interface
virtual std::string dump() const override {
+ struct tm* timeinfo = localtime(&mRealtimeSec);
+ const int8_t hour = static_cast<int8_t>(timeinfo->tm_hour);
+ const int8_t min = static_cast<int8_t>(timeinfo->tm_min);
+ const int8_t sec = static_cast<int8_t>(timeinfo->tm_sec);
+
std::ostringstream ss;
- ss << std::setfill('0') << std::setw(2) << static_cast<int>(mHour) << ":"
- << std::setw(2) << static_cast<int>(mMin) << ":"
- << std::setw(2) << static_cast<int>(mSec)
+ ss << std::setfill('0') << std::setw(2) << static_cast<int>(hour) << ":"
+ << std::setw(2) << static_cast<int>(min) << ":"
+ << std::setw(2) << static_cast<int>(sec)
<< (mActivated ? " +" : " -")
<< " 0x" << std::hex << std::setw(8) << mSensorHandle << std::dec
<< std::setfill(' ') << " pid=" << std::setw(5) << mPid
@@ -77,6 +82,25 @@
return ss.str();
}
+ /**
+ * Dump debugging information as android.service.SensorRegistrationInfoProto protobuf message
+ * using ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+ virtual void dump(util::ProtoOutputStream* proto) const override {
+ using namespace service::SensorRegistrationInfoProto;
+ proto->write(TIMESTAMP_SEC, int64_t(mRealtimeSec));
+ proto->write(SENSOR_HANDLE, mSensorHandle);
+ proto->write(PACKAGE_NAME, std::string(mPackageName.string()));
+ proto->write(PID, int32_t(mPid));
+ proto->write(UID, int32_t(mUid));
+ proto->write(SAMPLING_RATE_US, mSamplingRateUs);
+ proto->write(MAX_REPORT_LATENCY_US, mMaxReportLatencyUs);
+ proto->write(ACTIVATED, mActivated);
+ }
+
private:
int32_t mSensorHandle;
String8 mPackageName;
@@ -85,8 +109,7 @@
int64_t mSamplingRateUs;
int64_t mMaxReportLatencyUs;
bool mActivated;
- int8_t mHour, mMin, mSec;
-
+ time_t mRealtimeSec;
};
} // namespace android;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index c2e1204..e803c9a 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
#include <android/content/pm/IPackageManagerNative.h>
+#include <android/util/ProtoOutputStream.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <binder/ActivityManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
@@ -404,6 +406,8 @@
// Transition to data injection mode supported only from NORMAL mode.
return INVALID_OPERATION;
}
+ } else if (args.size() == 1 && args[0] == String16("--proto")) {
+ return dumpProtoLocked(fd, &connLock);
} else if (!mSensors.hasAnySensor()) {
result.append("No Sensors on the device\n");
result.appendFormat("devInitCheck : %d\n", SensorDevice::getInstance().initCheck());
@@ -506,6 +510,124 @@
return NO_ERROR;
}
+/**
+ * Dump debugging information as android.service.SensorServiceProto protobuf message using
+ * ProtoOutputStream.
+ *
+ * See proto definition and some notes about ProtoOutputStream in
+ * frameworks/base/core/proto/android/service/sensor_service.proto
+ */
+status_t SensorService::dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const {
+ using namespace service::SensorServiceProto;
+ util::ProtoOutputStream proto;
+ const bool privileged = IPCThreadState::self()->getCallingUid() == 0;
+
+ timespec curTime;
+ clock_gettime(CLOCK_REALTIME, &curTime);
+ proto.write(CURRENT_TIME_MS, curTime.tv_sec * 1000 + ns2ms(curTime.tv_nsec));
+
+ // Write SensorDeviceProto
+ uint64_t token = proto.start(SENSOR_DEVICE);
+ SensorDevice::getInstance().dump(&proto);
+ proto.end(token);
+
+ // Write SensorListProto
+ token = proto.start(SENSORS);
+ mSensors.dump(&proto);
+ proto.end(token);
+
+ // Write SensorFusionProto
+ token = proto.start(FUSION_STATE);
+ SensorFusion::getInstance().dump(&proto);
+ proto.end(token);
+
+ // Write SensorEventsProto
+ token = proto.start(SENSOR_EVENTS);
+ for (auto&& i : mRecentEvent) {
+ sp<SensorInterface> s = mSensors.getInterface(i.first);
+ if (!i.second->isEmpty()) {
+ i.second->setFormat(privileged || s->getSensor().getRequiredPermission().isEmpty() ?
+ "normal" : "mask_data");
+ const uint64_t mToken = proto.start(service::SensorEventsProto::RECENT_EVENTS_LOGS);
+ proto.write(service::SensorEventsProto::RecentEventsLog::NAME,
+ std::string(s->getSensor().getName().string()));
+ i.second->dump(&proto);
+ proto.end(mToken);
+ }
+ }
+ proto.end(token);
+
+ // Write ActiveSensorProto
+ SensorDevice& dev = SensorDevice::getInstance();
+ for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+ int handle = mActiveSensors.keyAt(i);
+ if (dev.isSensorActive(handle)) {
+ token = proto.start(ACTIVE_SENSORS);
+ proto.write(service::ActiveSensorProto::NAME,
+ std::string(getSensorName(handle).string()));
+ proto.write(service::ActiveSensorProto::HANDLE, handle);
+ proto.write(service::ActiveSensorProto::NUM_CONNECTIONS,
+ int(mActiveSensors.valueAt(i)->getNumConnections()));
+ proto.end(token);
+ }
+ }
+
+ proto.write(SOCKET_BUFFER_SIZE, int(mSocketBufferSize));
+ proto.write(SOCKET_BUFFER_SIZE_IN_EVENTS, int(mSocketBufferSize / sizeof(sensors_event_t)));
+ proto.write(WAKE_LOCK_ACQUIRED, mWakeLockAcquired);
+
+ switch(mCurrentOperatingMode) {
+ case NORMAL:
+ proto.write(OPERATING_MODE, OP_MODE_NORMAL);
+ break;
+ case RESTRICTED:
+ proto.write(OPERATING_MODE, OP_MODE_RESTRICTED);
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ break;
+ case DATA_INJECTION:
+ proto.write(OPERATING_MODE, OP_MODE_DATA_INJECTION);
+ proto.write(WHITELISTED_PACKAGE, std::string(mWhiteListedPackage.string()));
+ break;
+ default:
+ proto.write(OPERATING_MODE, OP_MODE_UNKNOWN);
+ }
+ proto.write(SENSOR_PRIVACY, mSensorPrivacyPolicy->isSensorPrivacyEnabled());
+
+ // Write repeated SensorEventConnectionProto
+ const auto& activeConnections = connLock->getActiveConnections();
+ for (size_t i = 0; i < activeConnections.size(); i++) {
+ token = proto.start(ACTIVE_CONNECTIONS);
+ activeConnections[i]->dump(&proto);
+ proto.end(token);
+ }
+
+ // Write repeated SensorDirectConnectionProto
+ const auto& directConnections = connLock->getDirectConnections();
+ for (size_t i = 0 ; i < directConnections.size() ; i++) {
+ token = proto.start(DIRECT_CONNECTIONS);
+ directConnections[i]->dump(&proto);
+ proto.end(token);
+ }
+
+ // Write repeated SensorRegistrationInfoProto
+ const int startIndex = mNextSensorRegIndex;
+ int curr = startIndex;
+ do {
+ const SensorRegistrationInfo& reg_info = mLastNSensorRegistrations[curr];
+ if (SensorRegistrationInfo::isSentinel(reg_info)) {
+ // Ignore sentinel, proceed to next item.
+ curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+ continue;
+ }
+ token = proto.start(PREVIOUS_REGISTRATIONS);
+ reg_info.dump(&proto);
+ proto.end(token);
+ curr = (curr + 1 + SENSOR_REGISTRATIONS_BUF_SIZE) % SENSOR_REGISTRATIONS_BUF_SIZE;
+ } while (startIndex != curr);
+
+ return proto.flush(fd) ? OK : UNKNOWN_ERROR;
+}
+
void SensorService::disableAllSensors() {
ConnectionSafeAutolock connLock = mConnectionHolder.lock(mLock);
disableAllSensorsLocked(&connLock);
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index fa23da0..7d17dda 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -286,6 +286,7 @@
virtual int setOperationParameter(
int32_t handle, int32_t type, const Vector<float> &floats, const Vector<int32_t> &ints);
virtual status_t dump(int fd, const Vector<String16>& args);
+ status_t dumpProtoLocked(int fd, ConnectionSafeAutolock* connLock) const;
String8 getSensorName(int handle) const;
bool isVirtualSensor(int handle) const;
sp<SensorInterface> getSensorInterfaceFromHandle(int handle) const;
diff --git a/services/sensorservice/SensorServiceUtils.h b/services/sensorservice/SensorServiceUtils.h
index 1558feb..49457cf 100644
--- a/services/sensorservice/SensorServiceUtils.h
+++ b/services/sensorservice/SensorServiceUtils.h
@@ -21,11 +21,17 @@
#include <string>
namespace android {
+
+namespace util {
+class ProtoOutputStream;
+}
+
namespace SensorServiceUtil {
class Dumpable {
public:
virtual std::string dump() const = 0;
+ virtual void dump(util::ProtoOutputStream*) const {}
virtual void setFormat(std::string ) {}
virtual ~Dumpable() {}
};
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 29688da..923a81c 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -115,6 +115,7 @@
void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
for (const auto& handle : mDrawingState.callbackHandles) {
handle->transformHint = mTransformHint;
+ handle->dequeueReadyTime = dequeueReadyTime;
}
mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
@@ -133,6 +134,14 @@
}
}
+void BufferStateLayer::finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->gpuCompositionDoneFence = glDoneFence;
+ handle->compositorTiming = compositorTiming;
+ }
+}
+
bool BufferStateLayer::shouldPresentNow(nsecs_t /*expectedPresentTime*/) const {
if (getSidebandStreamChanged() || getAutoRefresh()) {
return true;
@@ -149,6 +158,8 @@
!mLayerDetached;
}
+/* TODO: vhau uncomment once deferred transaction migration complete in
+ * WindowManager
void BufferStateLayer::pushPendingState() {
if (!mCurrentState.modified) {
return;
@@ -156,13 +167,12 @@
mPendingStates.push_back(mCurrentState);
ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
}
+*/
bool BufferStateLayer::applyPendingStates(Layer::State* stateToCommit) {
- const bool stateUpdateAvailable = !mPendingStates.empty();
- while (!mPendingStates.empty()) {
- popPendingState(stateToCommit);
- }
- mCurrentStateModified = stateUpdateAvailable && mCurrentState.modified;
+ mCurrentStateModified = mCurrentState.modified;
+ bool stateUpdateAvailable = Layer::applyPendingStates(stateToCommit);
+ mCurrentStateModified = stateUpdateAvailable && mCurrentStateModified;
mCurrentState.modified = false;
return stateUpdateAvailable;
}
@@ -244,14 +254,15 @@
return true;
}
-bool BufferStateLayer::updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
- nsecs_t desiredPresentTime) {
+bool BufferStateLayer::addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t desiredPresentTime) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mAcquireTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> acquireFenceTime =
std::make_shared<FenceTime>((acquireFence ? acquireFence : Fence::NO_FENCE));
NewFrameEventsEntry newTimestamps = {mCurrentState.frameNumber, postedTime, desiredPresentTime,
acquireFenceTime};
+ mFrameEventHistory.setProducerWantsEvents();
mFrameEventHistory.addQueue(newTimestamps);
return true;
}
@@ -276,12 +287,12 @@
mFlinger->mFrameTracer->traceNewLayer(layerId, getName().c_str());
mFlinger->mFrameTracer->traceTimestamp(layerId, buffer->getId(), mCurrentState.frameNumber,
postTime, FrameTracer::FrameEvent::POST);
+ desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime;
mCurrentState.desiredPresentTime = desiredPresentTime;
- mFlinger->mScheduler->recordLayerHistory(this,
- desiredPresentTime <= 0 ? 0 : desiredPresentTime);
+ mFlinger->mScheduler->recordLayerHistory(this, desiredPresentTime);
- updateFrameEventHistory(acquireFence, postTime, desiredPresentTime);
+ addFrameEvent(acquireFence, postTime, desiredPresentTime);
return true;
}
@@ -446,6 +457,13 @@
return mCurrentState.desiredPresentTime <= expectedPresentTime;
}
+bool BufferStateLayer::onPreComposition(nsecs_t refreshStartTime) {
+ for (const auto& handle : mDrawingState.callbackHandles) {
+ handle->refreshStartTime = refreshStartTime;
+ }
+ return BufferLayer::onPreComposition(refreshStartTime);
+}
+
uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mDrawingState.frameNumber;
}
@@ -529,6 +547,7 @@
for (auto& handle : mDrawingState.callbackHandles) {
handle->latchTime = latchTime;
+ handle->frameNumber = mDrawingState.frameNumber;
}
if (!SyncFeatures::getInstance().useNativeFenceSync()) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 57ff8bc..6ee5802 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -45,12 +45,17 @@
void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
+ void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& glDoneFence,
+ const CompositorTiming& compositorTiming) override;
+
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
}
- void pushPendingState() override;
+ /*TODO:vhau return to using BufferStateLayer override once WM
+ * has removed deferred transactions!
+ void pushPendingState() override;*/
bool applyPendingStates(Layer::State* stateToCommit) override;
uint32_t getActiveWidth(const Layer::State& s) const override { return s.active.w; }
@@ -78,6 +83,8 @@
bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
void forceSendCallbacks() override;
+ bool addFrameEvent(const sp<Fence>& acquireFence, nsecs_t postedTime,
+ nsecs_t requestedPresentTime) override;
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
@@ -104,6 +111,7 @@
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
+ bool onPreComposition(nsecs_t refreshStartTime) override;
protected:
void gatherBufferInfo() override;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 810e0af..de4a080 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -372,6 +372,10 @@
return false;
};
virtual void forceSendCallbacks() {}
+ virtual bool addFrameEvent(const sp<Fence>& /*acquireFence*/, nsecs_t /*postedTime*/,
+ nsecs_t /*requestedPresentTime*/) {
+ return false;
+ }
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
bool setShadowRadius(float shadowRadius);
@@ -596,6 +600,8 @@
// If a buffer was replaced this frame, release the former buffer
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
+ virtual void finalizeFrameEventHistory(const std::shared_ptr<FenceTime>& /*glDoneFence*/,
+ const CompositorTiming& /*compositorTiming*/) {}
/*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 33d85cb..c125b2c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2037,12 +2037,10 @@
ATRACE_CALL();
ALOGV("postComposition");
- // Release any buffers which were replaced this frame
nsecs_t dequeueReadyTime = systemTime();
for (auto& layer : mLayersWithQueuedFrames) {
layer->releasePendingBuffer(dequeueReadyTime);
}
-
// |mStateLock| not needed as we are on the main thread
const auto displayDevice = getDefaultDisplayDeviceLocked();
@@ -3349,6 +3347,11 @@
layer->pushPendingState();
}
+ // Only set by BLAST adapter layers
+ if (what & layer_state_t::eProducerDisconnect) {
+ layer->onDisconnect();
+ }
+
if (what & layer_state_t::ePositionChanged) {
if (layer->setPosition(s.x, s.y)) {
flags |= eTraversalNeeded;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index daa67ae..0cdff8f 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -237,9 +237,13 @@
// destroyed the client side is dead and there won't be anyone to send the callback to.
sp<IBinder> surfaceControl = handle->surfaceControl.promote();
if (surfaceControl) {
+ FrameEventHistoryStats eventStats(handle->frameNumber,
+ handle->gpuCompositionDoneFence->getSnapshot().fence,
+ handle->compositorTiming, handle->refreshStartTime,
+ handle->dequeueReadyTime);
transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
handle->previousReleaseFence,
- handle->transformHint);
+ handle->transformHint, eventStats);
}
return NO_ERROR;
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 12ea8fe..f50147a 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -45,6 +45,11 @@
nsecs_t acquireTime = -1;
nsecs_t latchTime = -1;
uint32_t transformHint = 0;
+ std::shared_ptr<FenceTime> gpuCompositionDoneFence{FenceTime::NO_FENCE};
+ CompositorTiming compositorTiming;
+ nsecs_t refreshStartTime = 0;
+ nsecs_t dequeueReadyTime = 0;
+ uint64_t frameNumber = 0;
};
class TransactionCompletedThread {
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
index 4e2b7c3..1318deb 100644
--- a/services/surfaceflinger/tests/utils/CallbackUtils.h
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -121,8 +121,10 @@
void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence, transformHint] =
- surfaceControlStats;
+ const auto&
+ [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+ transformHint,
+ frameEvents] = surfaceControlStats;
ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
<< "bad acquire time";