1 /* 2 * Copyright (C) 2016 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 17 package com.android.systemmetrics.functional; 18 19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION; 20 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS; 21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS; 22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_PROCESS_RUNNING; 23 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN; 24 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_REPORTED_DRAWN_MS; 25 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_STARTING_WINDOW_DELAY_MS; 26 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS; 27 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_CLASS_NAME; 28 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_COLD_LAUNCH; 29 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE; 30 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH; 31 import static junit.framework.TestCase.assertTrue; 32 import static org.junit.Assert.assertEquals; 33 import static org.junit.Assert.assertNotNull; 34 35 import android.content.Context; 36 import android.content.Intent; 37 import android.metrics.LogMaker; 38 import android.metrics.MetricsReader; 39 import android.os.SystemClock; 40 import android.support.test.InstrumentationRegistry; 41 import android.support.test.filters.MediumTest; 42 import android.support.test.metricshelper.MetricsAsserts; 43 import android.support.test.runner.AndroidJUnit4; 44 import android.support.test.uiautomator.By; 45 import android.support.test.uiautomator.UiDevice; 46 import android.support.test.uiautomator.Until; 47 import android.text.TextUtils; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 54 import java.util.Queue; 55 56 /** 57 * runtest --path platform_testing/tests/functional/systemmetrics/ 58 */ 59 @MediumTest 60 @RunWith(AndroidJUnit4.class) 61 public class AppStartTests { 62 private static final String LOG_TAG = AppStartTests.class.getSimpleName(); 63 private static final String SETTINGS_PACKAGE = "com.android.settings"; 64 private static final int LONG_TIMEOUT_MS = 2000; 65 private UiDevice mDevice = null; 66 private Context mContext; 67 private MetricsReader mMetricsReader; 68 private int mPreUptime; 69 70 @Before 71 public void setUp() throws Exception { 72 mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); 73 mContext = InstrumentationRegistry.getTargetContext(); 74 mDevice.setOrientationNatural(); 75 mMetricsReader = new MetricsReader(); 76 mMetricsReader.checkpoint(); // clear out old logs 77 mPreUptime = (int) (SystemClock.uptimeMillis() / 1000); 78 } 79 80 @After 81 public void tearDown() throws Exception { 82 mDevice.unfreezeRotation(); 83 mContext.startActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME)); 84 mDevice.waitForIdle(); 85 } 86 87 @Test 88 public void testStartApp() throws Exception { 89 Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(SETTINGS_PACKAGE); 90 91 // Clear out any previous instances 92 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); 93 94 assertNotNull("component name is null", intent.getComponent()); 95 String className = intent.getComponent().getClassName(); 96 String packageName = intent.getComponent().getPackageName(); 97 assertTrue("className is empty", !TextUtils.isEmpty(className)); 98 assertTrue("packageName is empty", !TextUtils.isEmpty(packageName)); 99 100 101 mContext.startActivity(intent); 102 mDevice.wait(Until.hasObject(By.pkg(SETTINGS_PACKAGE).depth(0)), LONG_TIMEOUT_MS); 103 104 int postUptime = (int) (SystemClock.uptimeMillis() / 1000); 105 106 Queue<LogMaker> startLogs = MetricsAsserts.findMatchingLogs(mMetricsReader, 107 new LogMaker(APP_TRANSITION)); 108 boolean found = false; 109 for (LogMaker log : startLogs) { 110 String actualClassName = (String) log.getTaggedData( 111 FIELD_CLASS_NAME); 112 String actualPackageName = log.getPackageName(); 113 if (className.equals(actualClassName) && packageName.equals(actualPackageName)) { 114 found = true; 115 int startUptime = ((Number) 116 log.getTaggedData(APP_TRANSITION_DEVICE_UPTIME_SECONDS)) 117 .intValue(); 118 assertTrue("must be either cold or warm launch", 119 TYPE_TRANSITION_COLD_LAUNCH == log.getType() 120 || TYPE_TRANSITION_WARM_LAUNCH == log.getType()); 121 assertTrue("reported uptime should be after the app was started", 122 mPreUptime <= startUptime); 123 assertTrue("reported uptime should be before assertion time", 124 startUptime <= postUptime); 125 assertNotNull("log should have delay", 126 log.getTaggedData(APP_TRANSITION_DELAY_MS)); 127 assertEquals("transition should be started because of starting window", 128 1 /* APP_TRANSITION_STARTING_WINDOW */, log.getSubtype()); 129 assertNotNull("log should have starting window delay", 130 log.getTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS)); 131 assertNotNull("log should have windows drawn delay", 132 log.getTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS)); 133 } 134 } 135 assertTrue("did not find the app start start log for: " 136 + intent.getComponent().flattenToShortString(), found); 137 } 138 139 @Test 140 public void testReportedDrawn() throws Exception { 141 Intent intent = new Intent(mContext, ReportedDrawnActivity.class).setFlags( 142 Intent.FLAG_ACTIVITY_NEW_TASK); 143 mContext.startActivity(intent); 144 mDevice.wait(Until.hasObject(By.pkg(mContext.getPackageName()).depth(0)), LONG_TIMEOUT_MS); 145 146 String className = intent.getComponent().getClassName(); 147 String packageName = intent.getComponent().getPackageName(); 148 149 // Sleep until activity under test has reported drawn (after 500ms) 150 SystemClock.sleep(1000); 151 Queue<LogMaker> startLogs = MetricsAsserts.findMatchingLogs(mMetricsReader, 152 new LogMaker(APP_TRANSITION_REPORTED_DRAWN)); 153 boolean found = false; 154 for (LogMaker log : startLogs) { 155 String actualClassName = (String) log.getTaggedData( 156 FIELD_CLASS_NAME); 157 String actualPackageName = log.getPackageName(); 158 if (className.equals(actualClassName) && packageName.equals(actualPackageName)) { 159 found = true; 160 assertTrue((long) log.getTaggedData(APP_TRANSITION_REPORTED_DRAWN_MS) > 500L); 161 assertEquals((int) log.getTaggedData(APP_TRANSITION_PROCESS_RUNNING), 1); 162 assertEquals(TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE, log.getType()); 163 } 164 } 165 assertTrue("did not find the app start start log for: " 166 + intent.getComponent().flattenToShortString(), found); 167 } 168 } 169