I've been looking at libbinder.so, specifically IPCThreadState.cpp, line 781
In libbinder.so, writes are serialized using this line: TextOutput::Bundle _b(alog); which locks a mutex.
The "call tree" for the writes is:
alog << "Sending commands to driver: " << indent;
template<typename T>
TextOutput& operator<<(TextOutput& to, const T& val)
{
std::stringstream strbuf;
strbuf << val;
std::string str = strbuf.str();
to.print(str.c_str(), str.size());
return to;
}
status_t BufferedTextOutput::print(const char* txt, size_t len)
virtual status_t writeLines(const struct iovec& vec, size_t N)
{
//android_writevLog(&vec, N); <-- this is now a no-op
if (N != 1) ALOGI("WARNING: writeLines N=%zu\n", N);
ALOGI("%.*s", (int)vec.iov_len, (const char*) vec.iov_base);
return NO_ERROR;
}
#define ALOGI(x...) fprintf(stderr, "svcmgr: " x)
I understand how writes to log are serialized within libbinder.so but how are writes serialized between multiple .so libraries?
libbinder.so writes to stderr but surely there are other libs that also write to stderr.
The lock is required to synchronize parts of the .<< chain. fprintf() is synchronized by the system.
It's going to come down to how the underlying libc (Bionic on Android, not glibc as commonly found on Linux) implemented stdout and stderr.
On Linux glibc buffers stdout at the line level; that is, any thread that writes anything to stdout, followed by a \n, that line will be printed on the terminal intact, not interleaved. In contrast, stderr is not buffered - it's output immediately, which means that two threads writing to stderr simulatanouesly will cause the output to be interleaved.
On Android I think (I am not an Android programmer) it's different. From what I can tell stdout and stderr are directed through to something called logcat. Kinda makes sense - there's no terminal on which stdout and stderr is displayed, so why not have it hoovered up by some service? I'm speculating, but I strongly suspect that all Bionic does with stderr and stdout is write data down an IPC pipe, with logcat at the other end.
The thing about pipes in the Linux kernel is that writes to the pipe are atomic (for writes below 4kbytes). So, as long as the application's thread's output to stdout or stderr results in a single call to write() to that IPC pipe, it will be atomic and therefore not interleaved. So if a thread in the application calls something like fprintf(stderr, "%i %s %c\n", var, str, c) and Bionic builds a string which it then submits to the IPC pipe with a single write(logcatpipe, buf, len), then you're good.
I re-emphasise that this is mere speculation; it might help further matters. But if it is correct, then you won't get interleaving no matter how many threads simultaneously write to stderr or stdout.
EDIT
This S.O. Question might be useful. The solutions there do seem to involve pipes, so if used then the pipe writes will be atomic, and you won't get interleaving.
Related
I'm writing a kernel driver for a Linux kernel running on Android devices (Nexus 5X).
I have a kernel buffer and I want to expose a device to read from it. I can read and write from the kernel buffer but I cannot write to the userspace buffer received from the read syscall. The very strange thing is that copy_to_user works only for less than 128 bytes... it makes no sense to me.
The code is the following ( truncated ):
static ssize_t dev_read(struct file *filep, char __user *buffer, size_t len, loff_t *offset){
unsigned long sent;
// ...
pr_err("MYLOGGER: copying from buffer: head=%d, tail=%d, cnt=%d, sent=%lu, access=%lu\n",
head, tail, cnt, sent,
access_ok(VERIFY_WRITE, buffer, sent));
if(sent >= 1) {
sent -= copy_to_user(buffer, mybuf + tail, sent);
pr_err("MYLOGGER: sent %lu bytes\n", sent);
// ...
}
// ...
}
The output is the following:
[ 56.476834] MYLOGGER: device opened
[ 56.476861] MYLOGGER: reading from buffer
[ 56.476872] MYLOGGER: copying from buffer: head=5666644, tail=0, cnt=5666644, sent=4096, access=1
[ 56.476882] MYLOGGER: sent 0 bytes
As you can see from the log sent is 4096, no integer overflow here.
When using dd I'm able to read up to 128 bytes per call ( dd if=/dev/mylog bs=128 ). I think that when using more than 128 bytes dd uses a buffer from the heap and the kernel cannot access it anymore, which is what I cannot understand.
I'm using copy_to_user from the read syscall handler, I've also printed the current->pid and it is the same process.
The kernel sources can be found from google android sources.
The function copy_to_user is defined at arch/arm64/include/asm/uaccess.h and the __copy_to_user can be found in arch/arm64/lib/copy_to_user.S.
Thank you for your time, I hope to get rid of this madness with your precious help.
-- EDIT --
I've wrote a small snippet to get the vm_area_struct of the destination userspace buffer and I print out the permissions, this is the result:
MYLOGGER: buffer belongs to vm_area with permissions rw-p
So that address should be writable...
-- EDIT --
I've written more debugging code, logging the state of the memory page used by the userspace buffer.
MYLOGGER: page=(0x7e3782d000-0x7e3782e000) present=1
Long story short it works when the page is present and will not cause a page fault. This is insanely weird, the page fault shall be managed by the virtual memory allocator that would load the page into the main memory...
For some reason, if the page is not present in memory the kernel will not fetch it.
My best guess is the __copy_to_user assembly function exception handler, which returns the number of uncopied bytes.
This exception handler is executed before the virtual memory page fault callback. Thus you won't be able to write to userspace unless the pages are already present in memory.
My current workaround is to preload those pages using get_user_pages.
I hope that this helps someone else :)
The problem was that I held a spin_lock.
copy_{to,from}_user shall never be called while holding a spin_lock.
Using a mutex solves the problem.
I feel so stupid to had wasted days on this...
I'm trying to build a C++ wrapper around libnfc to make a communication between my Android and the PN532 RFID module.
This helped me a lot: http://nfc-tools.org/index.php/Libnfc:APDU_example
This code is meant to send an APDU command where the body is contained in message (I'm not sending any header bytes etc.) and read the response into response.
Problem: If message exceeds 262 characters then I get a buffer overflow detected error. Otherwise it works perfectly well. I don't even think the error is thrown by the NFC library.
bool send(const std::string &message, std::string &response){
std::vector<uint8_t> apduCmd(message.begin(), message.end());
uint8_t *capdu = &apduCmd[0];
size_t capdulen = apduCmd.size();
uint8_t rapdu[10];
size_t rapdulen = 10;
// BUFFER OVERFLOW HERE
int res = nfc_initiator_transceive_bytes(m_nfcDevice, capdu, capdulen, rapdu, rapdulen, 500);
if (res<0) {
return false;
}
if(res<2 || rapdu[res-2] != 0x90 || rapdu[res-1] != 0x00){
return false;
}
// byteArrayToString omitting the last two bytes
response = byteArrayToString(rapdu, 0, res-2);
return true;
}
The limit of 262 bytes is a hard limit imposed the PN532 NFC chip. This is the maximum size of the raw data that can be sent (and received) in one InDataExchange command. libnfc explicitly enforces this limit for the method nfc_initiator_transceive_bytes() (see the definition of abtCmd in pn53x_initiator_transceive_bytes() and the definition of PN53x_EXTENDED_FRAME__DATA_MAX_LEN).
What you could do to overcome this limit, is to compose your own ISO/IEC 14443-4 blocks (using InCommunicateThru, i.e. nfc_initiator_transceive_bytes() with m_nfcDevice->bEasyFraming turned off. While each frame would still be limited to 263 bytes (the PN532 actually allows 264 bytes for InCommunicateThru but libnfc seems to limit this to 263 bytes), you can then pack your extended length APDUs into multiple ISO/IEC 14443-4 I-blocks. However, you would need to handle the whole ISO/IEC 14443-4 framing on your own (which means that you also have to take care of receive acknowledgements, etc.)
Finally, since the other communication endpoint is an Android device: Many Android devices do not support extended length APDUs. Consequently, even if you send longer APDUs, you might not be able to receive and process them on the Android side. Also, be aware that you should send proper APDUs conforming to the structures defined in ISO/IEC 7816-4 (i.e. APDUs with valid header and lengths fields), otherwise you might run into issues when talking to some devices.
The Android systrace logging system is fantastic, but it only works in the Java portion of the code, through Trace.beginSection() and Trace.endSection(). In a C/C++ NDK (native) portion of the code it can only be used through JNI, which is slow or unavailable in threads without a Java environment...
Is there any way of either adding events to the main systrace trace buffer, or even generating a separate log, from native C code?
This older question mentions atrace/ftrace as being the internal system Android's systrace uses. Can this be tapped into (easily)?
BONUS TWIST: Since tracing calls would often be in performance-critical sections, it should ideally be possible to run the calls after the actual event time. i.e. I for one would prefer to be able to specify the times to log, instead of the calls polling for it themselves. But that would just be icing on the cake.
Posting a follow-up answer with some code, based on fadden's pointers. Please read his/her answer first for the overview.
All it takes is writing properly formatted strings to /sys/kernel/debug/tracing/trace_marker, which can be opened without problems. Below is some very minimal code based on the cutils header and C file. I preferred to re-implement it instead of pulling in any dependencies, so if you care a lot about correctness check the rigorous implementation there, and/or add your own extra checks and error-handling.
This was tested to work on Android 4.4.2.
The trace file must first be opened, saving the file descriptor in an atrace_marker_fd global:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define ATRACE_MESSAGE_LEN 256
int atrace_marker_fd = -1;
void trace_init()
{
atrace_marker_fd = open("/sys/kernel/debug/tracing/trace_marker", O_WRONLY);
if (atrace_marker_fd == -1) { /* do error handling */ }
}
Normal 'nested' traces like the Java Trace.beginSection and Trace.endSection are obtained with:
inline void trace_begin(const char *name)
{
char buf[ATRACE_MESSAGE_LEN];
int len = snprintf(buf, ATRACE_MESSAGE_LEN, "B|%d|%s", getpid(), name);
write(atrace_marker_fd, buf, len);
}
inline void trace_end()
{
char c = 'E';
write(atrace_marker_fd, &c, 1);
}
Two more trace types are available, which are not accessible to Java as far as I know: trace counters and asynchronous traces.
Counters track the value of an integer and draw a little graph in the systrace HTML output. Very useful stuff:
inline void trace_counter(const char *name, const int value)
{
char buf[ATRACE_MESSAGE_LEN];
int len = snprintf(buf, ATRACE_MESSAGE_LEN, "C|%d|%s|%i", getpid(), name, value);
write(atrace_marker_fd, buf, len);
}
Asynchronous traces produce non-nested (i.e. simply overlapping) intervals. They show up as grey segments above the thin thread-state bar in the systrace HTML output. They take an extra 32-bit integer argument that "distinguishes simultaneous events". The same name and integer must be used when ending traces:
inline void trace_async_begin(const char *name, const int32_t cookie)
{
char buf[ATRACE_MESSAGE_LEN];
int len = snprintf(buf, ATRACE_MESSAGE_LEN, "S|%d|%s|%i", getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
inline void trace_async_end(const char *name, const int32_t cookie)
{
char buf[ATRACE_MESSAGE_LEN];
int len = snprintf(buf, ATRACE_MESSAGE_LEN, "F|%d|%s|%i", getpid(), name, cookie);
write(atrace_marker_fd, buf, len);
}
Finally, there indeed seems to be no way of specifying times to log, short of recompiling Android, so this doesn't do anything for the "bonus twist".
I don't think it's exposed from the NDK.
If you look at the sources, you can see that the android.os.Trace class calls into native code to do the actual work. That code calls atrace_begin() and atrace_end(), which are declared in a header in the cutils library.
You may be able to use the atrace functions directly if you extract the headers from the full source tree and link against the internal libraries. However, you can see from the header that atrace_begin() is simply:
static inline void atrace_begin(uint64_t tag, const char* name)
{
if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) {
char buf[ATRACE_MESSAGE_LENGTH];
size_t len;
len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name);
write(atrace_marker_fd, buf, len);
}
}
Events are written directly to the trace file descriptor. (Note that the timestamp is not part of the event; that's added automatically.) You could do something similar in your code; see atrace_init_once() in the .c file to see how the file is opened.
Bear in mind that, unless atrace is published as part of the NDK, any code using it would be non-portable and likely to fail in past or future versions of Android. However, as systrace is a debugging tool and not something you'd actually want to ship enabled in an app, compatibility is probably not a concern.
For anybody googling this question in the future.
Native trace events are supported since API Level 23, check out the docs here https://developer.android.com/topic/performance/tracing/custom-events-native.
Here's a simplified version of the code I'm using
Java:
private native void malloc(int bytes);
private native void free();
// this is called when I want to create a very large buffer in native memory
malloc(32 * 1024 * 1024);
// EDIT: after allocating, we need to initialize it before Android sees it as anythign other than a "reservation"
memset(blob, '\0', sizeof(char) * bytes);
...
// and when I'm done, I call this
free()
C:
static char* blob = NULL;
void Java_com_example_MyClass_malloc(JNIEnv * env, jobject this, jint bytes)
{
blob = (char*) malloc(sizeof(char) * bytes);
if (NULL == blob) {
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "Failed to allocate memory\n");
} else {
char m[50];
sprintf(m, "Allocated %d bytes", sizeof(char) * bytes);
__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, m);
}
}
void Java_com_example_MyClass_free(JNIEnv * env, jobject this)
{
free(blob);
blob = NULL;
}
Now when I call malloc() from MyClass.java, I would expect to see 32M of memory allocated and that I would be able to observe this drop in available memory somewhere.
I haven't seen any indication of that however, either in adb shell dumpsys meminfo or adb shell cat /proc/meminfo. I am pretty new to C, but have a bunch of Java experience. I'm looking to allocate a bunch of memory outside of Dalvik's heap (so it's not managed by Android/dalvik) for testing purposes. Hackbod has led me to believe that Android currently does not place restrictions on the amount of memory allocated in Native code, so this seems to be the correct approach. Am I doing this right?
You should see an increase in "private / dirty" pages after the memset(). If you have the extra developer command-line utilities installed on the device, you can run procrank or showmap <pid> to see this easily. Requires a rooted device.
Failing that, have the process copy the contents of /proc/self/maps to a file before and after the allocation. (Easiest is to write it to external storage; you'll need the WRITE_EXTERNAL_STORAGE permission in your manifest.) By comparing the map output you should either see a new 32MB region, or an existing region expanding by 32MB. This works because 32MB is above dlmalloc's internal-heap threshold, so the memory should be allocated using a call to mmap().
There is no fixed limit on the amount of memory you can allocate from native code. However, the more you allocate, the tastier you look to the kernel's low-memory process killer.
I have C code that uses prints with something clever like
printf("hello ");
// do something
printf(" world!\n");
which outputs
hello world!
I want to reuse that code with Android and iOS, but Log.d() and NSLog() effectively add a newline at the end of every string I pass them, so that the output of this code:
NSLog(#"hello ");
// do something
NSLog(#"world!\n");
comes out (more or less) as:
hello
world!
I'm willing to replace printf with some macro to make Log.d and NSLog emulate printf's handling of '\n'; any suggestions?
One solution that might work is to define a global log function that doesn't flush its buffer until it finds a newline.
Here's a (very) simple version in java for android:
import java.lang.StringBuilder;
class CustomLogger {
private static final StringBuilder buffer = new StringBuilder();
public static void log(String message) {
buffer.append(message);
if(message.indexOf('\n') != -1) {
Log.d('SomeTag', buffer);
buffer.setLength(0);
}
}
}
...
CustomLogger.log("Hello, ");
// Stuff
CustomLogger.log("world!\n"); // Now the message gets logged
It's completely untested but you get the idea.
This particular script has some performance issues. It might be better to check if just the last character is a newline for example.
I just realized that you wanted this in C. It shouldn't be too hard to port though a standard lib wouldn't hurt (to get stuff like a string buffer).
For progeny, this is what I did: store logged strings in a buffer, and print the part before the newline whenever there is a newline in the buffer.
Yes, the NDK logcat is dumb about it. There are ways to redirect stderr/stdout to logcat, but there are drawbacks (either need to "adb shell setprop" which is only for rooted devices, or a dup() like technique but creating a thread just for that purpose is not a good idea on embedded devices IMHO though you can look further below for this technique).
So I did my own function/macros for that purpose. Here are snippets. In a debug.c, do this:
#include "debug.h"
#include <stdio.h>
#include <stdarg.h>
static const char LOG_TAG[] = "jni";
void android_log(android_LogPriority type, const char *fmt, ...)
{
static char buf[1024];
static char *bp = buf;
va_list vl;
va_start(vl, fmt);
int available = sizeof(buf) - (bp - buf);
int nout = vsnprintf(bp, available, fmt, vl);
if (nout >= available) {
__android_log_write(type, LOG_TAG, buf);
__android_log_write(ANDROID_LOG_WARN, LOG_TAG, "previous log line has been truncated!");
bp = buf;
} else {
char *lastCR = strrchr(bp, '\n');
bp += nout;
if (lastCR) {
*lastCR = '\0';
__android_log_write(type, LOG_TAG, buf);
char *rest = lastCR+1;
int len = bp - rest; // strlen(rest)
memmove(buf, rest, len+1); // no strcpy (may overlap)
bp = buf + len;
}
}
va_end(vl);
}
Then in debug.h do this:
#include <android/log.h>
void android_log(android_LogPriority type, const char *fmt, ...);
#define LOGI(...) android_log(ANDROID_LOG_INFO, __VA_ARGS__)
#define LOGW(...) android_log(ANDROID_LOG_WARN, __VA_ARGS__)
...
Now you just need to include debug.hpp and call LOGI() with a printf-like semantic buffered until a '\n' is encountered (or buffer is full).
This is not perfect though, as if the string generated from a call is longer than the buffer, it will be truncated and output. But frankly, 1024 chars should be enough in most cases (even less than this). Anyway, if this happens it will output a warning so you know about it.
Also note the vsnprintf() is not standard C (but it works in Android NDK). We could use vsprintf() instead (which is standard), but it is unsafe on its own.
======================================================================
Now for the dup() technique, you can look here (James Moore answer).
Then you can get rid of the function above and define your macro as:
#define LOG(...) fprintf(stderr, ...)
and you're done.
Advantages:
C/C++ libraries often use stderr for their logs. Using dup is the only way to have their output in logcat without modifying their code (some big ones use hundreds of direct calls to fprintf(stderr, ...))
stderr is standard C used since decades. All standard C library functions related to streams can be used with it. Same for C++, you can even use cerr with << operator. It works since under the hood, it still stderr.
Very long lines not truncated (instead, their are split). A good reason to use a shorter buffer (256 in the example).
Disadvantages:
A thread on its own (though it's an IO only thread, impact is close to nothing)
No log priority value (INFO, WARN, ERROR, etc...) can be choosen during the call. It uses a default one (INFO), so DMMS will always show stderr lines in the same color.
You could always just build the string one segment at a time:
String message = "Hello";
// Do Something
message += " World!";
Log.v("Example", message);