1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.cts.oomcatcher; 17 18 import android.app.Activity; 19 import android.os.Bundle; 20 import android.app.ActivityManager; 21 import android.content.Context; 22 import android.content.ComponentCallbacks2; 23 import android.util.Log; 24 import java.util.concurrent.atomic.AtomicBoolean; 25 26 /* 27 * An App to report to logcat the lowmemory status. As soon as the app detects low memory, it 28 * immediately reports. In addition, it also reports every second. 29 */ 30 public class OomCatcher extends Activity implements ComponentCallbacks2 { 31 32 private static final String LOG_TAG = "OomCatcher"; 33 34 private AtomicBoolean isOom = new AtomicBoolean(false); 35 36 Thread logThread; 37 onCreate(Bundle savedInstanceState)38 public void onCreate(Bundle savedInstanceState) { 39 super.onCreate(savedInstanceState); 40 logThread = new Thread() { 41 @Override 42 public void run() { 43 while (true) { 44 logStatus(); 45 try { 46 Thread.sleep(1000); // 1 second 47 } catch (InterruptedException e) { 48 // thread has been killed 49 } 50 } 51 } 52 }; 53 logThread.setDaemon(true); 54 logThread.start(); 55 } 56 onDestroy()57 public void onDestroy() { 58 super.onDestroy(); 59 if (logThread != null) { 60 logThread.interrupt(); 61 } 62 } 63 64 /* 65 * Receive memory callbacks from the Android system. All report low memory except for 66 * TRIM_MEMORY_UI_HIDDEN, which reports when the app is in the background. We don't care about 67 * that, only when the device is at risk of OOMing. 68 * 69 * For all indications of low memory, onLowMemory() is called. 70 */ 71 @Override onTrimMemory(int level)72 public void onTrimMemory(int level) { 73 Log.i(LOG_TAG, "Memory trim level: " + level); 74 switch (level) { 75 // low priority messages being ignored 76 case TRIM_MEMORY_BACKGROUND: // bg 77 case TRIM_MEMORY_RUNNING_MODERATE: // fg 78 // fallthrough 79 Log.i(LOG_TAG, "ignoring low priority oom messages."); 80 break; 81 // medium priority messages being ignored 82 case TRIM_MEMORY_MODERATE: // bg 83 case TRIM_MEMORY_RUNNING_LOW: // fg 84 // fallthrough 85 Log.i(LOG_TAG, "ignoring medium priority oom messages."); 86 break; 87 // high priority messages 88 case TRIM_MEMORY_COMPLETE: // bg 89 case TRIM_MEMORY_RUNNING_CRITICAL: // fg 90 // fallthrough 91 onLowMemory(); 92 break; 93 case TRIM_MEMORY_UI_HIDDEN: 94 Log.i(LOG_TAG, "UI is hidden because the app is in the background."); 95 break; 96 default: 97 Log.i(LOG_TAG, "unknown memory trim message."); 98 return; 99 } 100 } 101 102 /* 103 * An earlier API implementation of low memory callbacks. Sets oom status and logs. 104 */ 105 @Override onLowMemory()106 public void onLowMemory() { 107 isOom.set(true); 108 logStatus(); 109 } 110 111 /* 112 * Log to logcat the current lowmemory status of the app. 113 */ logStatus()114 private void logStatus() { 115 Log.i(LOG_TAG, isOom.get() ? "Low memory" : "Normal memory"); 116 } 117 } 118