blob: 574b7705f9b00f44f4a341c514acd1f6ae3f7391 [file] [log] [blame]
Coding Style Guide for the Android emulator:
--------------------------------------------
Introduction:
-------------
IMPORTANT:
This guide only applies to the Android-specific code that is currently
found under $AOSP/external/qemu/android/ only. Other parts of
external/qemu/ should adhere to the QEMU coding style, whenever possible.
See the section name "Source Code Organization" for more details.
This document serves as a *guide* for anyone working on the Android-specific
portions of the Android emulator source code. Don't forget that consistency
for the sake of consistency is a waste of time. Use this information as a way
to speed up your coding and code reviews, first and foremost.
A .clang_format file is provided to automatically reformat your modified code
through 'git clang-format'. Use it, this will save you a lot of time.
Also, there is no real need to reformat existing code to adhere to the guide.
Would you feel the need to do so, do it in independent patches that batch all
reformatting without any bugfix / changes at all.
Each rule below comes with a rationale. Again, strict adherence is not
necessary.
IMPORTANT: You need to use 'git-config' to ensure 'git clang-format' works
correctly, see dedicated section below.
I. History:
-----------
This guide is a mix of the Android C++ coding style guide (not publicly
available) and the Chromium one, available at [1].
In case of doubt, fallback to the Chromium style guide.
II. Source Code Organization:
-----------------------------
It's important to understand when and how to apply this style guide.
The 'classic' Android emulator code base lives under $AOSP/external/qemu/,
with most of the Android-specific code under $AOSP/external/qemu/android/.
The 'qemu2' Android emulator code base lives under $AOSP/external/qemu/
and is *NOT* affected by this coding style guide.
external/qemu/android/base/
Set of low-level C++ interfaces to system facilities.
These should be completely self-contained (i.e. not depend on other
parts of the code base), and form the 'base platform' to rely on.
This is very similar (but simpler) than the Chromium base/ component.
*IMPORTANT*: Any new addition here should come with unit-tests that
will be run each time android/rebuild.sh runs.
Also see android/base/testing/ for helper classes to use
inside your unit tests.
Generally speaking, the use of C++ makes it easier to provide abstract
interfaces that can be replaced at runtime by mock versions. Doing so
in C is also possible, but requires more typing / is more error-prone.
This is very useful to be able to unit-test a sub-component without
having to run a full emulator session. In particular try to use the
features of base/system/System.h to access low-level system features,
this interface can be easily mocked during unit-tests by creating
an instance of base/testing/TestSystem.h, allowing your tests to not
depend on the state of the development machine whenever possible.
NOTE: Do not put high-level features here. Imagine you would reuse the
classes in this directory in a completely different program.
external/qemu/android/utils/
Similar low-level C-based interfaces, some of them are actual wrappers
for android/base/ features. Should not depend on anything else besides
system interfaces.
NOTE: Do not put high-level features here.
external/qemu/android-qemu1-glue/base/
Currently contains QEMU-specific implementations of android/base/
interfaces. E.g. android-qemu1-glue/base/async/Looper.h provides
android::qemu::createLooper(), which returns a Looper instance
based on the QEMU main event loop.
In this specific example, the idea is to use ThreadLooper::set() with
its result to inject it into the main thread. Any code that uses
ThreadLooper::get() to retrieve the current thread's Looper will use the
QEMU-based main loop when it runs within the emulator's main thread,
even if it doesn't know anything about QEMU.
This kind of decoupling is very useful and should be encouraged in
general.
external/qemu/android/<feature>/
Should contain code related to a specific feature used during emulation.
Ideally, the code should only depend on android/base/ and android/utils/,
stuff as much as possible. Anything that is QEMU-specific should be moved
somewhere else.
A good example is the GSM/SMS emulation code. Generic code is provided
under external/qemu/android/telephony/ (with unit-tests), while
QEMU-specific bindings are implemented under external/qemu/telephony/
which depend on it, and other QEMU headers / functions.
NOTE: It's essentially impossible to properly unit-test code that depends
on any QEMU-specific function, so move as much of your code as
possible out of it.
external/qemu/android/
The rest of the sources under this sub-directory are Android-specific
and is probably still a little bit messy. We plan to sort this out by
moving, over time, anything specific to QEMU outside of this directory.
*IMPORTANT*: The end goal is to ensure that the sources under
external/qemu/android/ will constitute a standalone component
that can be compiled as a standalone library, that doesn't
depend on the QEMU code, or its dependencies (e.g. GLib).
Ultimately, we plan to link the QEMU2 code base to the same
library, in order to ensure the same feature set for both the
classic and new emulator engines.
When adding new code, try hard to:
- Avoid using QEMU-specific functions directly. It's better to decouple
a 'clean' feature implementation, which can be unit-tested independently,
and a QEMU-specific binding / user code for it (which will ultimately
be re-implemented for QEMU2 as well).
- Avoid using system interfaces directly. Use the abstractions provided
by android/base/ and android/utils/ instead, since they can more easily
be mocked during unit-tests, making our regression test suite more
robust / less dependent on host/development system specifics.
The style guide applies to any new code you want to add under
external/qemu/android/ that should not depend on QEMU-specific headers and
declarations.
Finally, when adding new code, favor C++ over C if you can. The reason is
that it's easier to provide abstract / mockable interfaces in this language
compared to C. This leads to better de-coupling and unit-tests.
III. Rules:
-----------
As said previously, if something is not specified here, fall back to the
output of clang-format or the Chromium coding style guide at [1], otherwise
ask on the public mailing list for information.
1. Basic Code Formatting:
NOTE: Most of these should be handled automatically by 'git clang-format' !!
(See dedicated section below).
- No TABs in source code allowed (except for Makefiles).
Rationale: Life is too short to play with editor settings all the time.
- Indent width is 4 characters.
Rationale: Let's choose one reasonable default and stick with it.
- Continuation indentation should be 8 characters.
Rationale: This makes it slightly easier to detect that the second line
is really the continuation from the first one.
E.g.:
[YES]
SomeSuperLongTypeName someSuperLongVariableName =
CreateAnInstanceOfSomeSuperLongTypeName(withParameter);
[NO]
SomeSuperLongTypeName someSuperLongVariableName =
CreateAnInstanceOfSomeSuperLongTypeName(withParameter);
- Static word wrap at 80 characters.
Rationale: That's good enough, let's not fight about it.
- One space around each binary operator, e.g.:
x = y + z - 4;
- The opening curly brace is at the end of the line, e.g.:
void foo(int x) {
return x + 42;
}
Rationale: Let's just choose one convention, this one saves a little
vertical space.
- Single-statements conditionals can go into a single line, and always use
accolades:
if (error) { [YES]
return ENOPE;
}
if (error) { return ENOPE; } [YES]
if (error)
return ENOPE; [NO]
if (error) return ENOPE; [NO]
if (error) { return ENOPE; } else { return 0; } [NO] // not single-statement
if (error) { [YES]
return ENOPE;
} else {
return 0;
}
return error ? ENOPE : 0; [YES]
Rationale: Reduces the chance of introducing subtle bug later when
adding more statements. Sadly this still happens occasionally
to everyone.
- The closing curly brace should appear at the start of its own line, or at
the end of the line containing the opening brace:
E.g.:
Foo::Foo() {} [YES]
if (cond) { [YES]
doStuffA();
} else {
doStuffB();
}
if (cond) { return error; } [YES]
- The * and & go by the type rather than the variable name, e.g.:
void foo(const char* str); [YES]
void foo(const char * str); [NO]
void foo(const char *str); [NO]
Rationale: it's more logical since they're really part of the type.
Special exception: a space is allowed for casts, as in:
return static_cast<const char*>(foo); [YES]
return static_cast<const char *>(foo); [YES]
Because there is no ambiguity that this is part of the type.
- Don't indent within namespaces, and always add a comment when closing one,
which should be exactly: '}' + 2 spaces + '// namespace' eventually
followed by the namespace name if any, e.g.:
[GOOD]
namespace android {
namespace foo {
namespace {
... declarations inside anonymous namespace
} // namespace <--- declare end of anonymous namespace
// Declares android::foo::Foo
class Foo {
...
};
} // namespace foo
} // namespace android
- C++ member initialization in constructors should happen either on a single
line, or use one line per member, with member initializations aligned
after the colon, e.g.:
class Foo {
public:
Foo()
: mFirstMember(),
mSecondMember(),
mThirdMember(),
mFourthMember() {}
....
};
2. Naming:
- C++ class/struct names follow 'CapitalCamelCase'
- C++ Functions and methods follow 'lowerCamelCase()'
- C++ Class member names begin with an 'm' prefix, as in mFoo, mBar, ...
- For C++ structs that are POD types (i.e. no constructor/destructor/virtual
methods and private members), you can use 'lowerCamelCase' instead for
(necessarily public) members.
- C++ variables names use 'lowerCamelCase' or 'lower_underscore_spacing' to
your convenience.
- C types names follow 'CapitalCamelCase' as well.
- C functions should preferably use 'lowerCamelCase'. Sometimes an underscore
can be used to prefix a family of related functions though, as in:
sandwich_grabCondiments()
sandwich_addSauce()
sandwich_putBread()
- When implementing 'C with classes', follow 'objectType_methodName',
and distinguish between functions that allocate objects in the heap,
and those that only initialize them in place.
typedef struct FooBar FooBar;
FooBar* fooBar_new(); // Allocate and initialize.
void fooBar_free(FooBar* fooBar); // Finalize and release.
void fooBar_resetColor(FooBar* fooBar, int newColor);
// NOTE: _create() and _destroy() are also valid suffixes for
functions that also perform heap allocation/releases.
typedef struct {
... field declarations.
} Zoo;
void zoo_init(Zoo* bar, ...); // Initialize instance in place.
void zoo_done(Zoo* bar); // Finalize instance.
NOTE: The 'this' parameter always comes first.
- C++ header files should be named according to the main class they declare
and follow 'CapitalCamelCase.h'.
C header files should be named similarly, but should use
'lower_underscore_spacing.h' instead. That's actually a simple way to
differentiate between both header types.
- Don't use header inclusion guard macros, use '#pragma once' since it's
supported by all our compilers now. I.e.
// Copyright disclaimer blah blah
// ....
#pragma once
... declarations
Instead of:
// Copyright disclaimer blah blah
// ....
#ifndef ANDROID_STUFF_FOO_BAR_H
#define ANDROID_STUFF_FOO_BAR_H
... declarations
#endif // ANDROID_STUFF_FOO_BAR_H
- C++ namespace names are 'all_lowercase', and avoid using underscores
if possible. Nested namespaces are ok, but use 'android' as the top-level
one to avoid conflicts in the future when we need to include headers from
other third-party C++ libraries (e.g. 'android::base', 'android::testing',
etc)
- C++ constants like unscoped enum values and static character arrays
should be named using a 'k' prefix followed by CamelCase, as in:
enum Mode {
kRead = 1 << 0,
kWrite = 1 << 1,
kReadWrite = kRead | kWrite;
};
static char kString[] = "Hello World";
Note that scoped enums (a.k.a. 'enum classes') don't need the k Prefix
but should still use CamelCasing as in:
enum class Mode {
Read = 1 << 0, // Mode::Read
Write = 1 << 1, // Mode::Write
ReadWrite = Read | Write // Mode::ReadWrite
};
3. Comments:
- Favor C++ style comments even in C source files.
Rationale: They are easier to edit, and all recent C toolchains support
then now.
- When declaring a new C++ class, begin with a comment explaining its
purpose and a usage example. Don't comment on the implementation though.
- Document each parameter and the result of each function or method.
Use |paramName| notation to denote a given parameter, or expression that
uses the parameter inside the comment to make it clearer.
- Inside the code, use comments to describe the code's intended behaviour,
not the exact implementation. Anything that is subtle should have a comment
that explain why things are the way they are, including temporary band-aids,
work-arounds and 'clever hacks' to help future maintenance.
- Try to add comments after #else and #endif directives to indicate what
they relate to, as in:
#ifdef _WIN32
...
#endif // !_WIN32
#if defined(__linux__) || defined(_WIN32)
...
#else // !__linux__ && !_WIN32 <-- NOTE: condition inverted on #else
...
#endif // !__linux__ && !_WIN32
4. Header and ordering:
When including header files, follow this order:
- Each source file should first include the header file it relates to,
using "" notation, with path relative to external/qemu/.
For example, the source file 'android/myfeature/Foo.cpp' might use:
#include "android/myfeature/Foo.h" [YES]
But not:
#include <android/myfeature/Foo.h> [NO]
#include "Foo.h" [NO]
Rationale: If you end up not including a required header in
your_fancy_module.h, then you catch that mistake while trying to
compile your_fancy_module.c, instead of someone else hitting it later
when including your_fancy_module.h in their client code.
- Then list all other headers from the android/ sub-directory,
use case-insensitive alphabetical ordering to do this, with ""
notation, e.g.:
android/myfeature/Api.cpp:
#include "android/myfeature/Api.h"
#include "android/base/Log.h"
#include "android/myfeature/Helper.h"
#include "android/otherFeather.h"
- Followed by all headers from third-party libraries, using <> notation.
- Followed by all system headers, using <> notation.
Separate each header group with an empty line.
5. Unnamed namespaces:
Contrary to the Chromium style guide, avoid them if you want.
Rationale: Their main drawback is that it's extremely difficult to set
breakpoints into functions that are defined into anonymous namespaces with
GDB during debugging. I.e. you need to manually quote the full type with ("),
and auto-completion doesn't work. This is really not cool when you're already
having a hard time trying to undestand why something doesn't work.
Internal functions declared with 'static' don't have this problem.
It might be a good idea to put whole internal classes declarations inside
unnamed namespaces though to avoid exporting all its symbols in the
corresponding object file, and use better relocations as well, e.g.:
namespace {
class MySuperDuperClass : public BaseClass {
.... // lots of methods here.
};
} // namespace
BaseClass* createSuperDuperInstance() {
return new MySuperDuperClass();
}
6. Platform-specific code:
We don't provide OS_XXX macros, so currently use the following checks for
host-platform conditional checks:
#ifdef _WIN32
... Code specific to 32-bit and 64-bit Windows!
#endif // _WIN32
#ifdef __linux__
... Code specific to Linux
#endif // __linux__
#ifdef __APPLE__
... Code specific to Darwin / OS X
#endif // __APPLE__
#ifndef _WIN32
... Code specific to Linux or Darwin.
#endif // !_WIN32
By the way, refer to OS X as 'darwin' instead in your comments and source
file names if possible.
IV. Automatic code formatting with 'git clang-format':
------------------------------------------------------
A file is provided at external/qemu/android/.clang-format that contains rules
to apply with the 'clang-format' tool. More specifically, one should do the
following to manually reformat entire sources:
cd external/qemu/android/
clang-format -style=file -i <list-of-files>
The '-style=file' option is required to tell clang-format to use our
.clang-format file, otherwise, it will default to the Google style which
is quite different!
You can also use the 'git clang-format' command, that will only reformat
the lines that you have currently modified and added to your index, however
you need to configure your git project once to ensure it uses the .clang-format
file properly, with:
git config clangformat.style file
This ensures that git will pass '-style=file' to clang-format each time you
call 'git clang-format' (which itself calls git-clang-format).
V. C++11 and beyond
As of now, C++11 is enabled for all platforms, and here's the allowed
features (list is also based on Chromium style [1], but a little more
relaxed):
0. First of all, be consistent.
If you're editing some older file which has a bunch of 'typedef's, don't just
throw 'using' in the middle of them. Either follow the existing pattern, or
upgrade around your change. Consistency helps the reader much more than some
single fancy feature.
1. auto
Use auto when type is obvious, not important or hard to spell:
good:
auto i = 0;
auto foo = new Foo();
auto it = map.begin();
bad:
auto f = doSomeStuff();
otherStuff(f->bar());
Don't forget about "auto&" and "const auto&" to make sure the value is not
copied or accidentally modified.
2. foreach loop
Use the foreach loop for iteration over everything you can
int values[] = {1,2,3};
for (int i : values) {
...
}
Use the correct reference form for the variable (& or const &); don't
just throw &&
3. Uniform initialization and initializer lists
Prefer uniform initialization syntax {} to disambugate variables from
functions and suppress implicit type conversions.
int i = 1.0; // bad, precision loss
int i = {1.0}; // good, compiler error
Foo f(); // bad, function f returning foo instead of a variable
Foo f{}; // good, default-initialized variable f
4. type aliases
Prefer "using" over "typedef"
// easier to understand - "=" splits alias and the actual type
using f = foo::bar::baz;
// much simpler for functions than typedefed version -
// typedef char (*func)(blah)[10];
using func = char (*)(blah)[10];
// typedef cannot into templates :)
template <class T>
using vec<T> = std::vector<T, our_super_duper_allocator<T>>;
5. override and final
Use these new keywords as much as possible to make sure your derived class
actually overrides someting from a base class.
6. Defaulted and deleted members
Prefer "= default" and "= delete" syntax over the empty braces and private
declaration. It both improves readability and compiler messages/generated
code.
Note: you can use this syntax in the implementation file:
foo.h:
struct Foo {
Foo();
};
foo.cpp:
Foo::Foo() = default;
7. Class member initializers
Use member initializers instead of a standalone constructor if that's the
only thing it is needed for, or if there are many constructors all requiring
the same member values
class Meow {
public:
Meow() = default;
Meow(int i) : i(i) {
}
private:
int i = 0;
int j = 2;
std::string meow = "meow";
};
8. Strongly-typed enums
Prefer scoped enums, a.k.a. "enum classes", over the old unscoped enums.
I.e.:
[YES]
enum class Mode {
Read = 1 << 0,
Write = 1 << 1,
ReadWrite = (1 << 0) | (1 << 1),
};
[NO]
enum Mode {
kRead = 1 << 0,
kWrite = 1 << 1,
kReadWrite = kRead | kWrite,
};
Note: Scoped enums have one drawback: they do not support bitwise operations
which are typically handy for dealing with bitflags. There is
fortunately one solution for this, which is to include
"android/base/EnumFlags.h" in your source file, and add the
following flag if you're not in the android::base namespace:
#include "android/base/EnumFlags.h"
...
using ::android::base::EnumFlags
9. static_assert
Use where possible over the runtime assert() calls
10. Raw string literals
Use raw string literals for the things which otherwise look horrible
auto s = R"(text with lots of "bad" characters\xml\etc
even
many
newlines)";
11. STL updates
TEMPORARY: no C++11 STL features work on Mac with its default library
until we switch to libc++, STL is limited to C++03
DISABLED: Feel free to use all new features from the STL, but make sure they
DISABLED: actually compile and work on all platforms: Linux, Mac and Windows.
DISABLED: Take extra care with the Windows MinGW - it tends to lag for quite a lot
DISABLED: compare to others, e.g. std::thread is still unavaliable out of the box
DISABLED: Something may not compile, others could be implemented a little differently.
DISABLED: Do your due diligence before actually submitting the change.
DISABLED: Prefer STL implementations over a handwritten code, e.g. std::atomic,
DISABLED: std smart pointers, regexes, etc
99. lambdas, noexcept, rvalue references, move semantics, perfect forwarding,
constexpr
Do not use the features listed here.
...unless:
- You need to return a move-only type, e.g. std::unique_ptr<>. Use
std::move(var) for this case.
MAX_INT. Other features not mentioned here
If there's some missing feature you need, just add it to the list and send a
code review to the team.
V. Contributing code
-----------------------------
CL descriptions should follow the form (copied off of [2]):
submodule: Summary of change preferably < 65 chars, surely < 80
Longer description of change addressing as appropriate: why the change is made,
context if it is part of many changes, description of previous behavior and
newly introduced differences, etc.
Long lines should be wrapped to 80 columns for easier log message viewing in
terminals.
BUG=b.android.com/123456
TEST=Optional description of test steps to be performed by a human to verify
this patch. This helps cherry-pick changes later.
For bug fixes, it's a manual regression test (or preferably, just "Run
(new) unittests" :) ). For new features, some sanity checks.
M. Appendix
-----------------------------
[1] https://www.chromium.org/developers/coding-style
[2] https://www.chromium.org/developers/contributing-code