1 /* 2 * Copyright (C) 2016 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.google.android.mobly.snippet.util; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.PackageManager; 22 import android.content.pm.PackageManager.NameNotFoundException; 23 import android.os.Bundle; 24 25 public final class Log { 26 public static volatile String apkLogTag = null; 27 28 private static final String MY_CLASS_NAME = Log.class.getName(); 29 private static final String ANDROID_LOG_CLASS_NAME = android.util.Log.class.getName(); 30 31 // Skip the first two entries in stack trace when trying to infer the caller. 32 // The first two entries are: 33 // - dalvik.system.VMStack.getThreadStackTrace(Native Method) 34 // - java.lang.Thread.getStackTrace(Thread.java:580) 35 // The {@code getStackTrace()} function returns the stack trace at where the trace is collected 36 // (inisde the JNI function {@code getThreadStackTrace()} instead of at where the {@code 37 // getStackTrace()} is called (althrought this is the natual expectation). 38 private static final int STACK_TRACE_WALK_START_INDEX = 2; 39 Log()40 private Log() {} 41 initLogTag(Context context)42 public static synchronized void initLogTag(Context context) { 43 if (apkLogTag != null) { 44 throw new IllegalStateException("Logger should not be re-initialized"); 45 } 46 String packageName = context.getPackageName(); 47 PackageManager packageManager = context.getPackageManager(); 48 ApplicationInfo appInfo; 49 try { 50 appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA); 51 } catch (NameNotFoundException e) { 52 throw new IllegalStateException( 53 "Failed to find ApplicationInfo with package name: " + packageName); 54 } 55 Bundle bundle = appInfo.metaData; 56 apkLogTag = bundle.getString("mobly-log-tag"); 57 if (apkLogTag == null) { 58 apkLogTag = packageName; 59 w( 60 "AndroidManifest.xml does not contain metadata field named \"mobly-log-tag\". " 61 + "Using package name for logging instead."); 62 } 63 } 64 getTag()65 private static String getTag() { 66 String logTag = apkLogTag; 67 if (logTag == null) { 68 throw new IllegalStateException("Logging called before initLogTag()"); 69 } 70 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); 71 72 boolean isCallerClassNameFound = false; 73 String fullClassName = null; 74 int lineNumber = 0; 75 // Walk up the stack and look for the first class name that is neither us nor 76 // android.util.Log: that's the caller. 77 // Do not used hard-coded stack depth: that does not work all the time because of proguard 78 // inline optimization. 79 for (int i = STACK_TRACE_WALK_START_INDEX; i < stackTraceElements.length; i++) { 80 StackTraceElement element = stackTraceElements[i]; 81 fullClassName = element.getClassName(); 82 if (!fullClassName.equals(MY_CLASS_NAME) 83 && !fullClassName.equals(ANDROID_LOG_CLASS_NAME)) { 84 lineNumber = element.getLineNumber(); 85 isCallerClassNameFound = true; 86 break; 87 } 88 } 89 90 if (!isCallerClassNameFound) { 91 // Failed to determine caller's class name, fall back the the minimal one. 92 return logTag; 93 } else { 94 String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1); 95 return logTag + "." + className + ":" + lineNumber; 96 } 97 } 98 v(String message)99 public static void v(String message) { 100 android.util.Log.v(getTag(), message); 101 } 102 v(String message, Throwable e)103 public static void v(String message, Throwable e) { 104 android.util.Log.v(getTag(), message, e); 105 } 106 e(Throwable e)107 public static void e(Throwable e) { 108 android.util.Log.e(getTag(), "Error", e); 109 } 110 e(String message)111 public static void e(String message) { 112 android.util.Log.e(getTag(), message); 113 } 114 e(String message, Throwable e)115 public static void e(String message, Throwable e) { 116 android.util.Log.e(getTag(), message, e); 117 } 118 w(Throwable e)119 public static void w(Throwable e) { 120 android.util.Log.w(getTag(), "Warning", e); 121 } 122 w(String message)123 public static void w(String message) { 124 android.util.Log.w(getTag(), message); 125 } 126 w(String message, Throwable e)127 public static void w(String message, Throwable e) { 128 android.util.Log.w(getTag(), message, e); 129 } 130 d(String message)131 public static void d(String message) { 132 android.util.Log.d(getTag(), message); 133 } 134 d(String message, Throwable e)135 public static void d(String message, Throwable e) { 136 android.util.Log.d(getTag(), message, e); 137 } 138 i(String message)139 public static void i(String message) { 140 android.util.Log.i(getTag(), message); 141 } 142 i(String message, Throwable e)143 public static void i(String message, Throwable e) { 144 android.util.Log.i(getTag(), message, e); 145 } 146 } 147