#include "jtraceAPI.h" #include #include "../colors.h" #include // Sample plugin for JTrace API - for lmkd // ---------------------------- // // I made the API very simple but (hopefully) effective - q.v. the H file, // which I've fully documented. // // Basically, you create a dylib, // // Please direct any suggestions for improvements, or additional APIs // you may want to me via NewAndroidBook.com // // // These are from lmkd.h // enum lmk_cmd { LMK_TARGET = 0, /* Associate minfree with oom_adj_score */ LMK_PROCPRIO, /* Register a process and set its oom_adj_score */ LMK_PROCREMOVE, /* Unregister a process */ LMK_PROCPURGE, /* Purge all registered processes */ LMK_GETKILLCNT, /* Get number of kills */ LMK_SUBSCRIBE, /* Subscribe for asynchronous events */ LMK_PROCKILL, /* Unsolicited msg to subscribed clients on proc kills */ LMK_UPDATE_PROPS, /* Reinit properties */ LMK_STAT_KILL_OCCURRED, /* Unsolicited msg to subscribed clients on proc kills for statsd log */ LMK_STAT_STATE_CHANGED, /* Unsolicited msg to subscribed clients on state changed */ }; /* LMK_TARGET payload: */ struct lmk_target { int minfree; int oom_adj_score; }; struct lmk_procprio { pid_t pid; uid_t uid; int oomadj; }; extern int config_color (void); int gColor ; int lmkd_recvmsg (int Exit, int Pid) { char *ob = getOutputBuffer (); uint32_t pos =0; int readRC = 0; if (!Exit) { long arg0 = getRegValue(REG_ARG_0); saveRegValue(REG_ARG_0); if (arg0 > 255) { fprintf(stderr,"read %ld?!\n", arg0);} pos += sprintf(ob+pos, "%srecvmsg%s (", config_color()? BOLD :"", config_color()?NORMAL:""); pos += sprintf (ob+pos, "%ld", arg0); pos+=sprintf (ob+pos,","); updateOutputBufferPos(pos); return 0; } else { // on exit, print values read. Use jtrace's readProcessMemory // unsigned long addr = getRegValue(REG_ARG_1); readRC = getRegValue (REG_ARG_RETVAL); char *fdName = getFDName (getSavedRegValue(REG_ARG_0)); int format = 0; if (fdName && strcmp(fdName, "/dev/socket/lmkd") ==0) { // fd should be /dev/socket/lmkd, since that's the // only thing that lmkd read(2)s from.. // I use alloca because it's simpler and faster // caveat: if readRC is too big, it would explode // the stack. Either check readRC or use malloc.. // (but lmkd never reads much..) // uint32_t len = getRegValue(2); char *buffer = getIOVecDataFromMsgHdr ((struct msghdr *) getRegValue(1), &len, Pid); // pos+=hexDumpToBuffer(ob +pos, 1000, buffer, len, getRegValue(1), 1); if (!buffer) { pos += sprintf(ob+pos,""); } else { uint32_t *cmd = (uint32_t *) buffer; // nice trick would be to use union here. // struct lmk_procprio *pp = (struct lmk_procprio *)(cmd + 1); if (gColor) { pos+= sprintf(ob+pos,BLUE); } uint32_t c = ntohl(*cmd); switch (c) { case LMK_TARGET: pos+= sprintf(ob+pos,"LMK_TARGET: \n"); break; case LMK_PROCPRIO: pos+= sprintf(ob+pos,"LMK_PROCPRIO: PID %d (UID %d) set to %d", ntohl(pp->pid), ntohl(pp->uid), ntohl(pp->oomadj)); break; case LMK_PROCREMOVE: pos+= sprintf (ob+pos,"LMK_PROCREMOVE: PID %d", ntohl(pp->pid)); break; default: pos += sprintf(ob+pos, "Unhandled command 0x%x\n", c); } } } else { fprintf(stderr,"descriptor not a socket?\n"); } } if (gColor) { pos += sprintf(ob +pos, NORMAL); } pos += sprintf(ob+pos, ")= %d", readRC); updateOutputBufferPos(pos); return 0; } // lmkd_read int init = 0; __attribute__((constructor)) void _init(void) { if (init) return; init++; fprintf(stderr,"LOADED LMKD PLUGIN\n"); gColor = config_color(); int rc= registerSyscallHandler ("recvmsg", // char *SyscallName, // must exist or you'll get -1 lmkd_recvmsg, // syscall_handler_func Handler, // Your callback, per above 0, // int Bitness, // 32, 64 or 0 (both) 0); // int Flags); // as per flags, above }