Home | History | Annotate | Download | only in jni
      1 // Copyright 2017 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "libmemtrack_wrapper.h"
      6 
      7 #include <dlfcn.h>
      8 
      9 #include "logging.h"
     10 
     11 namespace {
     12 
     13 // Init memtrack service. Removed in the latest version.
     14 int (*memtrack_init)(void);
     15 
     16 // Allocate and dispose memory stats.
     17 libmemtrack_proc* (*memtrack_proc_new)(void);
     18 void (*memtrack_proc_destroy)(libmemtrack_proc* p);
     19 
     20 // Query memory stats for given process.
     21 int (*memtrack_proc_get)(libmemtrack_proc* p, pid_t pid);
     22 
     23 // Since memory stats is opaque structure, there are helpers to parse it.
     24 ssize_t (*memtrack_proc_graphics_total)(libmemtrack_proc* p);
     25 ssize_t (*memtrack_proc_graphics_pss)(libmemtrack_proc* p);
     26 ssize_t (*memtrack_proc_gl_total)(libmemtrack_proc* p);
     27 ssize_t (*memtrack_proc_gl_pss)(libmemtrack_proc* p);
     28 ssize_t (*memtrack_proc_other_total)(libmemtrack_proc* p);
     29 ssize_t (*memtrack_proc_other_pss)(libmemtrack_proc* p);
     30 
     31 typedef ssize_t (*libmemtrack_getter_t)(libmemtrack_proc*);
     32 
     33 bool g_initialized = false;
     34 bool g_broken = false;
     35 
     36 template <typename T>
     37 void Import(T** func, void* lib, const char* name) {
     38   *(reinterpret_cast<void**>(func)) = dlsym(lib, name);
     39 }
     40 
     41 bool ImportLibmemtrackSymbols(void* handle) {
     42   Import(&memtrack_init, handle, "memtrack_init");
     43   Import(&memtrack_proc_new, handle, "memtrack_proc_new");
     44   Import(&memtrack_proc_destroy, handle, "memtrack_proc_destroy");
     45   Import(&memtrack_proc_get, handle, "memtrack_proc_get");
     46   Import(&memtrack_proc_graphics_total, handle, "memtrack_proc_graphics_total");
     47   Import(&memtrack_proc_graphics_pss, handle, "memtrack_proc_graphics_pss");
     48   Import(&memtrack_proc_gl_total, handle, "memtrack_proc_gl_total");
     49   Import(&memtrack_proc_gl_pss, handle, "memtrack_proc_gl_pss");
     50   Import(&memtrack_proc_other_total, handle, "memtrack_proc_other_total");
     51   Import(&memtrack_proc_other_pss, handle, "memtrack_proc_other_pss");
     52 
     53   if (!memtrack_proc_new || !memtrack_proc_destroy || !memtrack_proc_get) {
     54     LogError("Couldn't use libmemtrack. Probably it's API has been changed.");
     55     return false;
     56   }
     57   // Initialization is required on pre-O Android.
     58   if (memtrack_init && memtrack_init() != 0) {
     59     LogError("Failed to initialize libmemtrack. "
     60              "Probably implementation is missing in the ROM.");
     61     return false;
     62   }
     63   return true;
     64 }
     65 
     66 bool LazyOpenLibmemtrack() {
     67   if (g_initialized)
     68     return true;
     69   if (g_broken)
     70     return false;
     71 
     72   void *handle = dlopen("libmemtrack.so", RTLD_GLOBAL | RTLD_NOW);
     73   if (handle == nullptr) {
     74     LogError("Failed to open libmemtrack library.");
     75     g_broken = true;
     76     return false;
     77   }
     78 
     79   if (!ImportLibmemtrackSymbols(handle)) {
     80     dlclose(handle);
     81     g_broken = true;
     82     return false;
     83   }
     84 
     85   g_initialized = true;
     86   return true;
     87 }
     88 
     89 uint64_t GetOrZero(libmemtrack_getter_t getter, libmemtrack_proc* proc) {
     90   if (!getter || !proc)
     91     return 0;
     92   return static_cast<uint64_t>(getter(proc));
     93 }
     94 
     95 }  // namespace
     96 
     97 MemtrackProc::MemtrackProc(int pid) {
     98   if (!LazyOpenLibmemtrack())
     99     return;
    100 
    101   proc_ = memtrack_proc_new();
    102   if (!proc_) {
    103     LogError("Failed to create libmemtrack proc. "
    104              "Probably it's API has been changed.");
    105     return;
    106   }
    107 
    108   if (memtrack_proc_get(proc_, pid) != 0) {
    109     // Don't log an error since not every process has memtrack stats.
    110     memtrack_proc_destroy(proc_);
    111     proc_ = nullptr;
    112   }
    113 }
    114 
    115 MemtrackProc::~MemtrackProc() {
    116   if (proc_)
    117     memtrack_proc_destroy(proc_);
    118 }
    119 
    120 uint64_t MemtrackProc::graphics_total() const {
    121   return GetOrZero(memtrack_proc_graphics_total, proc_);
    122 }
    123 
    124 uint64_t MemtrackProc::graphics_pss() const {
    125   return GetOrZero(memtrack_proc_graphics_pss, proc_);
    126 }
    127 
    128 uint64_t MemtrackProc::gl_total() const {
    129   return GetOrZero(memtrack_proc_gl_total, proc_);
    130 }
    131 
    132 uint64_t MemtrackProc::gl_pss() const {
    133   return GetOrZero(memtrack_proc_gl_pss, proc_);
    134 }
    135 
    136 uint64_t MemtrackProc::other_total() const {
    137   return GetOrZero(memtrack_proc_other_total, proc_);
    138 }
    139 
    140 uint64_t MemtrackProc::other_pss() const {
    141   return GetOrZero(memtrack_proc_other_pss, proc_);
    142 }
    143