blob: 65f415ab0217587305fb5d7157e1b8ac644b5d37 [file] [log] [blame]
/*
* Copyright (C) 2010 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 A_DEBUG_H_
#define A_DEBUG_H_
#include <string.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
#include <utils/Log.h>
inline static const char *asString(android::status_t i, const char *def = "??") {
using namespace android;
switch (i) {
case NO_ERROR: return "NO_ERROR";
case UNKNOWN_ERROR: return "UNKNOWN_ERROR";
case NO_MEMORY: return "NO_MEMORY";
case INVALID_OPERATION: return "INVALID_OPERATION";
case BAD_VALUE: return "BAD_VALUE";
case BAD_TYPE: return "BAD_TYPE";
case NAME_NOT_FOUND: return "NAME_NOT_FOUND";
case PERMISSION_DENIED: return "PERMISSION_DENIED";
case NO_INIT: return "NO_INIT";
case ALREADY_EXISTS: return "ALREADY_EXISTS";
case DEAD_OBJECT: return "DEAD_OBJECT";
case FAILED_TRANSACTION: return "FAILED_TRANSACTION";
case BAD_INDEX: return "BAD_INDEX";
case NOT_ENOUGH_DATA: return "NOT_ENOUGH_DATA";
case WOULD_BLOCK: return "WOULD_BLOCK";
case TIMED_OUT: return "TIMED_OUT";
case UNKNOWN_TRANSACTION: return "UNKNOWN_TRANSACTION";
case FDS_NOT_ALLOWED: return "FDS_NOT_ALLOWED";
default: return def;
}
}
namespace android {
#define LITERAL_TO_STRING_INTERNAL(x) #x
#define LITERAL_TO_STRING(x) LITERAL_TO_STRING_INTERNAL(x)
#define CHECK(condition) \
LOG_ALWAYS_FATAL_IF( \
!(condition), \
"%s", \
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" CHECK(" #condition ") failed.")
#define MAKE_COMPARATOR(suffix,op) \
template<class A, class B> \
AString Compare_##suffix(const A &a, const B &b) { \
AString res; \
if (!(a op b)) { \
res.append(a); \
res.append(" vs. "); \
res.append(b); \
} \
return res; \
}
MAKE_COMPARATOR(EQ,==)
MAKE_COMPARATOR(NE,!=)
MAKE_COMPARATOR(LE,<=)
MAKE_COMPARATOR(GE,>=)
MAKE_COMPARATOR(LT,<)
MAKE_COMPARATOR(GT,>)
#define CHECK_OP(x,y,suffix,op) \
do { \
AString ___res = Compare_##suffix(x, y); \
if (!___res.empty()) { \
AString ___full = \
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" CHECK_" #suffix "( " #x "," #y ") failed: "; \
___full.append(___res); \
\
LOG_ALWAYS_FATAL("%s", ___full.c_str()); \
} \
} while (false)
#define CHECK_EQ(x,y) CHECK_OP(x,y,EQ,==)
#define CHECK_NE(x,y) CHECK_OP(x,y,NE,!=)
#define CHECK_LE(x,y) CHECK_OP(x,y,LE,<=)
#define CHECK_LT(x,y) CHECK_OP(x,y,LT,<)
#define CHECK_GE(x,y) CHECK_OP(x,y,GE,>=)
#define CHECK_GT(x,y) CHECK_OP(x,y,GT,>)
#define TRESPASS() \
LOG_ALWAYS_FATAL( \
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" Should not be here.");
struct ADebug {
enum Level {
kDebugNone, // no debug
kDebugLifeCycle, // lifecycle events: creation/deletion
kDebugState, // commands and events
kDebugConfig, // configuration
kDebugInternalState, // internal state changes
kDebugAll, // all
kDebugMax = kDebugAll,
};
// parse the property or string to get a long-type level for a component name
// string format is:
// <level>[:<glob>][,<level>[:<glob>]...]
// - <level> is 0-5 corresponding to ADebug::Level
// - <glob> is used to match component name case insensitively, if omitted, it
// matches all components
// - string is read left-to-right, and the last matching level is returned, or
// the def if no terms matched
static long GetLevelFromSettingsString(
const char *name, const char *value, long def);
static long GetLevelFromProperty(
const char *name, const char *value, long def);
// same for ADebug::Level - performs clamping to valid debug ranges
static Level GetDebugLevelFromProperty(
const char *name, const char *propertyName, Level def = kDebugNone);
// remove redundant segments of a codec name, and return a newly allocated
// string suitable for debugging
static char *GetDebugName(const char *name);
inline static bool isExperimentEnabled(
const char *name __unused /* nonnull */, bool allow __unused = true) {
#ifdef ENABLE_STAGEFRIGHT_EXPERIMENTS
if (!strcmp(name, "legacy-adaptive")) {
return getExperimentFlag(allow, name, 2, 1); // every other day
} else if (!strcmp(name, "legacy-setsurface")) {
return getExperimentFlag(allow, name, 3, 1); // every third day
} else {
ALOGE("unknown experiment '%s' (disabled)", name);
}
#endif
return false;
}
private:
// pass in allow, so we can print in the log if the experiment is disabled
static bool getExperimentFlag(
bool allow, const char *name, uint64_t modulo, uint64_t limit,
uint64_t plus = 0, uint64_t timeDivisor = 24 * 60 * 60 /* 1 day */);
};
} // namespace android
#endif // A_DEBUG_H_