1 /* 2 * Copyright (C) 2018 The Android Open Source Project 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.android.launcher3.tapl; 18 19 import static androidx.test.InstrumentationRegistry.getInstrumentation; 20 import static androidx.test.InstrumentationRegistry.getTargetContext; 21 22 import android.app.Instrumentation; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.pm.ActivityInfo; 27 import android.content.pm.ResolveInfo; 28 import android.content.res.Resources; 29 import android.os.DropBoxManager; 30 import android.os.SystemClock; 31 import android.util.Log; 32 33 import androidx.test.uiautomator.SearchCondition; 34 import androidx.test.uiautomator.UiDevice; 35 36 import java.util.Date; 37 import java.util.List; 38 import java.util.Objects; 39 40 public class TestHelpers { 41 42 private static final String TAG = "Tapl"; 43 private static Boolean sIsInLauncherProcess; 44 isInLauncherProcess()45 public static boolean isInLauncherProcess() { 46 if (sIsInLauncherProcess == null) { 47 sIsInLauncherProcess = initIsInLauncherProcess(); 48 } 49 return sIsInLauncherProcess; 50 } 51 initIsInLauncherProcess()52 private static boolean initIsInLauncherProcess() { 53 ActivityInfo info = getLauncherInMyProcess(); 54 55 // If we are in the same process, we can instantiate the class name. 56 try { 57 Class launcherClazz = Class.forName("com.android.launcher3.Launcher"); 58 return launcherClazz.isAssignableFrom(Class.forName(info.name)); 59 } catch (Exception e) { 60 return false; 61 } 62 } 63 getHomeIntentInPackage(Context context)64 public static Intent getHomeIntentInPackage(Context context) { 65 return new Intent(Intent.ACTION_MAIN) 66 .addCategory(Intent.CATEGORY_HOME) 67 .setPackage(context.getPackageName()) 68 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 69 } 70 getLauncherInMyProcess()71 public static ActivityInfo getLauncherInMyProcess() { 72 Instrumentation instrumentation = getInstrumentation(); 73 if (instrumentation.getTargetContext() == null) { 74 return null; 75 } 76 77 List<ResolveInfo> launchers = getTargetContext().getPackageManager() 78 .queryIntentActivities(getHomeIntentInPackage(getTargetContext()), 0); 79 if (launchers.size() != 1) { 80 return null; 81 } 82 return launchers.get(0).activityInfo; 83 } 84 getOverviewComponentName()85 public static ComponentName getOverviewComponentName() { 86 Resources res = Resources.getSystem(); 87 int id = res.getIdentifier("config_recentsComponentName", "string", "android"); 88 if (id != 0) { 89 return ComponentName.unflattenFromString(res.getString(id)); 90 } 91 return new ComponentName("com.android.systemui", 92 "com.android.systemui.recents.RecentsActivity"); 93 } 94 getOverviewPackageName()95 public static String getOverviewPackageName() { 96 return getOverviewComponentName().getPackageName(); 97 } 98 truncateCrash(String text, int maxLines)99 private static String truncateCrash(String text, int maxLines) { 100 String[] lines = text.split("\\r?\\n"); 101 StringBuilder ret = new StringBuilder(); 102 for (int i = 0; i < maxLines && i < lines.length; i++) { 103 ret.append(lines[i]); 104 ret.append('\n'); 105 } 106 if (lines.length > maxLines) { 107 ret.append("... "); 108 ret.append(lines.length - maxLines); 109 ret.append(" more lines truncated ...\n"); 110 } 111 return ret.toString(); 112 } 113 checkCrash(Context context, String label, long startTime)114 private static String checkCrash(Context context, String label, long startTime) { 115 DropBoxManager dropbox = Objects.requireNonNull( 116 context.getSystemService(DropBoxManager.class)); 117 118 long timestamp = startTime; 119 DropBoxManager.Entry entry; 120 StringBuilder errorDetails = new StringBuilder(); 121 while (null != (entry = dropbox.getNextEntry(label, timestamp))) { 122 errorDetails.append("------------------------------\n"); 123 timestamp = entry.getTimeMillis(); 124 errorDetails.append(new Date(timestamp)); 125 errorDetails.append(": "); 126 errorDetails.append(entry.getTag()); 127 errorDetails.append(": "); 128 final String dropboxSnippet = entry.getText(4096); 129 if (dropboxSnippet != null) errorDetails.append(truncateCrash(dropboxSnippet, 40)); 130 errorDetails.append(" ...\n"); 131 entry.close(); 132 } 133 return errorDetails.length() != 0 ? errorDetails.toString() : null; 134 } 135 getSystemHealthMessage(Context context, long startTime)136 public static String getSystemHealthMessage(Context context, long startTime) { 137 try { 138 StringBuilder errors = new StringBuilder(); 139 140 final String[] labels = { 141 "system_app_anr", 142 "system_app_crash", 143 "system_app_native_crash", 144 "system_server_anr", 145 "system_server_crash", 146 "system_server_native_crash", 147 "system_server_watchdog", 148 }; 149 150 for (String label : labels) { 151 final String crash = checkCrash(context, label, startTime); 152 if (crash != null) errors.append(crash); 153 } 154 155 return errors.length() != 0 156 ? "Current time: " + new Date(System.currentTimeMillis()) + "\n" + errors 157 : null; 158 } catch (Exception e) { 159 return null; 160 } 161 } 162 wait(SearchCondition<R> condition, long timeout)163 public static <R> R wait(SearchCondition<R> condition, long timeout) { 164 Log.d(TAG, 165 "TestHelpers.wait, condition=" + timeout + ", time=" + SystemClock.uptimeMillis()); 166 final R result = UiDevice.getInstance(getInstrumentation()).wait(condition, timeout); 167 Log.d(TAG, "TestHelpers.wait, result=" + result + ", time=" + SystemClock.uptimeMillis()); 168 return result; 169 } 170 } 171