blob: f63fb042e3610f24d377cfee6e739b876aaa3e48 [file] [log] [blame]
/*
* Copyright (C) 2016 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.
*/
#ifndef GAPII_CALL_OBSERVER_H
#define GAPII_CALL_OBSERVER_H
#include "abort_exception.h"
#include "gles_types.h"
#include "slice.h"
#include <gapic/coder/atom.h>
#include <gapic/interval_list.h>
#include <gapic/scratch_allocator.h>
#include <gapic/vector.h>
namespace gapii {
typedef uint32_t GLenum_Error;
class SpyBase;
// CallObserver collects observation data in API function calls. It is supposed
// to be created at the beginning of each intercepted API function call and
// deleted at the end.
class CallObserver {
public:
typedef gapic::coder::atom::Observation Observation;
CallObserver(SpyBase* spy_p);
~CallObserver();
// setCurrentCommandName sets the name of the current command that is being
// observed by this observer. The storage of cmd_name must remain valid for
// the lifetime of this observer object, ideally it should be static
// string.
void setCurrentCommandName(const char* cmd_name) {
mCurrentCommandName = cmd_name;
}
const char* getCurrentCommandName() { return mCurrentCommandName; }
// Get or set the GL error code for this call.
GLenum_Error getError() { return mError; }
void setError(GLenum_Error err) { mError = err; }
// getScratch returns a scratch allocator which holds the temporary memory
// assigned to this observer. The memory assigned to this allocator will be
// released when CallObserver is destructed.
// TODO(qining): Implementation for a real thread-local allocator is
// required.
gapic::DefaultScratchAllocator* getScratch() { return &mScratch; }
// read is called to make a read memory observation of size bytes, starting
// at base. It only records the range of the read memory, the actual
// copying of the data is deferred until the data is to be sent.
void read(const void* base, uint64_t size);
// write is called to make a write memory observation of size bytes,
// starting at base. It only records the range of the write memory, the
// actual copying of the data is deferred until the data is to be sent.
void write(const void* base, uint64_t size);
// observeReads observes all the pending read memory observations into
// mObservations.mReads. The list of pending memory observations is
// cleared on returning.
inline void observeReads();
// observeWrites observes all the pending write memory observations into
// mObservations.mWrites. The list of pending memory observations is
// cleared on returning.
inline void observeWrites();
// read records the memory range for the given slice as a read operation.
// The actual copying of the data is deferred until the data is to be sent.
template <typename T>
inline void read(const Slice<T>& slice);
// read records and returns the i'th element from the slice src. The actual
// copying of the data is deferred until the data is to be sent.
template <typename T>
inline T read(const Slice<T>& src, uint64_t i);
// write records the memory for the given slice as a write operation. The
// actual copying of the data is deferred until the data is to be sent.
template <typename T>
inline void write(const Slice<T>& slice);
// write records a value to i'th element in the slice dst. The actual
// copying of the data is deferred until the data is to be sent.
template <typename T>
inline void write(const Slice<T>& dst, uint64_t i, const T& value);
// copy copies N elements from src to dst, where N is the smaller of
// src.count() and dst.count().
// copy observes the sub-slice of src as a read operation. The sub-slice
// of dst is returned so that the write observation can be made after the
// call to the imported function.
template <typename T>
inline Slice<T> copy(const Slice<T>& dst, const Slice<T>& src);
// clone observes src as a read operation and returns a copy of src in a
// new Pool.
template <typename T>
inline Slice<T> clone(const Slice<T>& src);
// string returns a std::string from the null-terminated string str.
// str is observed as a read operation.
inline std::string string(const char* str);
// string returns a std::string from the Slice<char> slice.
// slice is observed as a read operation.
inline std::string string(const Slice<char>& slice);
// observe observes all the pending memory observations, returning the list
// of observations made.
// The list of pending memory observations is cleared on returning.
void observe(gapic::Vector<Observation>& observations);
// getExtras return the list of atom extras to be appended to the current
// atom.
gapic::Vector<gapic::Encodable*>& getExtras() {
return mExtras;
}
void addExtra(gapic::Encodable* extra) {
mExtras.append(extra);
}
private:
// shouldObserve returns true if the given slice is located in application
// pool and we are supposed to observe application pool.
template <class T>
bool shouldObserve(const Slice<T>& slice) const {
return mObserveApplicationPool && slice.isApplicationPool();
}
// Make a slice on a new Pool.
template <typename T>
inline Slice<T> make(uint64_t count) const;
// A pointer to the spy instance.
SpyBase* mSpyPtr;
// A pointer to the static array that contains the current command name.
const char* mCurrentCommandName;
// True if we should observe the application poool.
bool mObserveApplicationPool;
// A pre-allocated memory allocator to store observation data.
gapic::DefaultScratchAllocator mScratch;
// The observations extra that will be bundled in atom writes.
gapic::coder::atom::Observations* mObservations;
// The list of pending reads or writes observations that are yet to be made.
gapic::IntervalList<uintptr_t> mPendingObservations;
// The list of pending extras to be appended to the atom.
gapic::Vector<gapic::Encodable*> mExtras;
// Record GL error which was raised during this call.
GLenum_Error mError;
};
inline void CallObserver::observeReads() {
if (mPendingObservations.count() > 0) {
if (mObservations == nullptr) {
mObservations = mScratch.create<gapic::coder::atom::Observations>();
addExtra(mObservations);
}
observe(mObservations->mReads);
}
}
inline void CallObserver::observeWrites() {
if (mPendingObservations.count() > 0) {
if (mObservations == nullptr) {
mObservations = mScratch.create<gapic::coder::atom::Observations>();
addExtra(mObservations);
}
observe(mObservations->mWrites);
}
}
template <typename T>
inline void CallObserver::read(const Slice<T>& slice) {
if (shouldObserve(slice)) {
read(slice.begin(), slice.count() * sizeof(T));
}
}
template <typename T>
inline T CallObserver::read(const Slice<T>& src, uint64_t index) {
T& elem = src[index];
if (shouldObserve(src)) {
read(&elem, sizeof(T));
}
return elem;
}
template <typename T>
inline void CallObserver::write(const Slice<T>& slice) {
if (shouldObserve(slice)) {
write(slice.begin(), slice.count() * sizeof(T));
}
}
template <typename T>
inline void CallObserver::write(const Slice<T>& dst, uint64_t index,
const T& value) {
if (!shouldObserve(
dst)) { // The spy must not mutate data in the application pool.
dst[index] = value;
} else {
write(&dst[index], sizeof(T));
}
}
template <typename T>
inline Slice<T> CallObserver::copy(const Slice<T>& dst, const Slice<T>& src) {
read(src);
if (!shouldObserve(
dst)) { // The spy must not mutate data in the application pool.
uint64_t c = (src.count() < dst.count()) ? src.count() : dst.count();
src.copy(dst, 0, c, 0);
}
return dst;
}
template <typename T>
inline Slice<T> CallObserver::clone(const Slice<T>& src) {
Slice<T> dst = make<T>(src.count());
copy(dst, src);
return dst;
}
template <typename T>
inline Slice<T> CallObserver::make(uint64_t count) const {
auto pool = Pool::create(count * sizeof(T));
return Slice<T>(reinterpret_cast<T*>(pool->base()), count, pool);
}
inline std::string CallObserver::string(const char* str) {
checkNotNull(str);
for (uint64_t i = 0;; i++) {
if (str[i] == 0) {
read(str, i + 1);
return std::string(str, str + i);
}
}
}
inline std::string CallObserver::string(const Slice<char>& slice) {
read(slice);
return std::string(slice.begin(), slice.end());
}
} // namespace gapii
#endif // GAPII_CALL_OBSERVER_H