I used the ASM framework to instrument framework-minus-apex.jar in AOSP of Android 11 and 12. The instrumented code collects method invocation information and writes a trace to a file. The instrumentation is successful and the phone with the instrumented frameowork.jar can boot. The problem is, the AtomicInteger I used in the trace output class is not atomic, that is, I have duplicate value in my trace after analyzing it.
The trace output class is like follows, the AtomicInteger is named _globalEventID:
package trace;
import android.os.SystemClock;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;
public class TraceRecorderBinary {
private static int _eventLength = 18;
private static final AtomicLong _globalEventID = new AtomicLong(0);
protected static File _traceFile = new File("/sdcard/trace");
private static FileOutputStream _fo = null;
private static final int BUFSIZE = _eventLength * 1024 * 1024;
private static byte[] _buf = new byte[BUFSIZE];
private static int _bufCap = 0;
private static ReentrantLock _gidLock = new ReentrantLock();
private static ReentrantLock _timerLock = new ReentrantLock();
private static ReentrantLock _outLock = new ReentrantLock();
//private static long _time = System.nanoTime();
public TraceRecorderBinary() {
super();
try {
_outLock.lock();
if (_fo == null && _traceFile.exists()) {
_fo = new FileOutputStream(_traceFile, true);
} else if (_fo != null && !_traceFile.exists()) {
_fo.close();
_fo = null;
_bufCap = 0;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
_outLock.unlock();
}
}
protected final static long getTime() {
/*
Though wrapped by a lock, the time also repeats.
*/
_timerLock.lock();
// long ret = System.currentTimeMillis();
long ret = SystemClock.elapsedRealtime();
_timerLock.unlock();
return ret;
}
protected final static int getGlobalID() {
/*
Though wrapped by a lock, the value still repeats.
*/
_gidLock.lock();
int ret = (int) _globalEventID.getAndIncrement();
_gidLock.unlock();
return ret;
}
private static void putBuf(byte[] bs) {
try {
_outLock.lock();
if (_fo != null) {
if (bs.length != _eventLength) {
return;
}
if (_bufCap == BUFSIZE) {
_fo.write(_buf);
_bufCap = 0;
}
System.arraycopy(bs, 0, _buf, _bufCap, bs.length);
_bufCap += _eventLength;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
_outLock.unlock();
}
}
final private void putEvent(int method_id) {
_outLock.lock();
if (_fo == null) {
_outLock.unlock();
return;
}
_outLock.unlock();
byte[] b = new byte[_eventLength];
short _threadID = (short) Thread.currentThread().getId();
int global_eid = getGlobalID();
long time = getTime();
// little-endian
b[1] = (byte) ((_threadID >> 8) & 0xFF);
b[0] = (byte) (_threadID & 0xFF);
b[5] = (byte) ((method_id >> 24) & 0xff);
b[4] = (byte) ((method_id >> 16) & 0xff);
b[3] = (byte) ((method_id >> 8) & 0xff);
b[2] = (byte) (method_id & 0xff);
b[9] = (byte) ((global_eid >> 24) & 0xff);
b[8] = (byte) ((global_eid >> 16) & 0xff);
b[7] = (byte) ((global_eid >> 8) & 0xff);
b[6] = (byte) (global_eid & 0xff);
b[17] = (byte) ((time >> 56) & 0xff);
b[16] = (byte) ((time >> 48) & 0xff);
b[15] = (byte) ((time >> 40) & 0xff);
b[14] = (byte) ((time >> 32) & 0xff);
b[13] = (byte) ((time >> 24) & 0xff);
b[12] = (byte) ((time >> 16) & 0xff);
b[11] = (byte) ((time >> 8) & 0xff);
b[10] = (byte) (time & 0xff);
putBuf(b);
}
/*
This method is invoked by the bytecode inserted at almost
every method in the framework.
*/
public void onMethodEnter(int method_id) {
putEvent(method_id);
}
}
Even though I used ReentrantLock, the time and gid still have duplicates.
I also tried the commented field,
private static long _time = System.nanoTime();
to see if the duplication is due to class loading or something like that, yet this _time stays the same throughout the trace.
So, any ideas? Thanks.