Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4104b83 authored by Omari Stephens's avatar Omari Stephens Committed by Android (Google) Code Review
Browse files

Merge "Add a method to the smoke test that launches each app"

parents 5f9d991b 9f5a511a
Loading
Loading
Loading
Loading
+164 −14
Original line number Diff line number Diff line
@@ -19,12 +19,21 @@ package com.android.smoketest;
import com.android.internal.os.RuntimeInit;

import android.app.ActivityManager;
import android.app.ActivityManager.ProcessErrorStateInfo;
import android.content.Context;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.test.AndroidTestCase;
import android.util.Log;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

/**
 * This smoke test is designed to quickly sniff for any error conditions
@@ -32,37 +41,109 @@ import java.util.List;
 */
public class ProcessErrorsTest extends AndroidTestCase {
    
    private final String TAG = "ProcessErrorsTest";
    private static final String TAG = "ProcessErrorsTest";
    
    protected ActivityManager mActivityManager;
    protected PackageManager mPackageManager;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        mActivityManager = (ActivityManager)
                getContext().getSystemService(Context.ACTIVITY_SERVICE);
        mPackageManager = getContext().getPackageManager();
    }

    public void testSetUpConditions() throws Exception {
        assertNotNull(mActivityManager);
        assertNotNull(mPackageManager);
    }

    public void testNoProcessErrors() throws Exception {
        List<ActivityManager.ProcessErrorStateInfo> errList;        
        final String reportMsg = checkForProcessErrors();
        if (reportMsg != null) {
            Log.w(TAG, reportMsg);
        }

        // report a non-empty list back to the test framework
        assertNull(reportMsg, reportMsg);
    }

    private String checkForProcessErrors() throws Exception {
        List<ProcessErrorStateInfo> errList;
        errList = mActivityManager.getProcessesInErrorState();
        
        // note: this contains information about each process that is currently in an error
        // condition.  if the list is empty (null) then "we're good".  
        
        // if the list is non-empty, then it's useful to report the contents of the list
        // we'll put a copy in the log, and we'll report it back to the framework via the assert.
        final String reportMsg = reportListContents(errList);
        if (reportMsg != null) {
            Log.w(TAG, reportMsg);
        return reportMsg;
    }

        // report a non-empty list back to the test framework
        assertNull(reportMsg, errList);
    /**
     * A test that runs all Launcher-launchable activities and verifies that no ANRs or crashes
     * happened while doing so.
     * <p />
     * FIXME: Doesn't detect multiple crashing apps properly, since the crash dialog for the
     * FIXME: first app doesn't go away.
     */
    public void testRunAllActivities() throws Exception {
        final Intent home = new Intent(Intent.ACTION_MAIN);
        home.addCategory(Intent.CATEGORY_HOME);
        home.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

        final Intent launchable = new Intent(Intent.ACTION_MAIN);
        launchable.addCategory(Intent.CATEGORY_LAUNCHER);
        final List<ResolveInfo> activities = mPackageManager.queryIntentActivities(launchable, 0);
        final Set<ProcessError> errSet = new HashSet<ProcessError>();

        for (ResolveInfo info : activities) {
            Log.i(TAG, String.format("Got %s/%s", info.activityInfo.packageName,
                    info.activityInfo.name));

            // build an Intent to launch the app
            final ComponentName component = new ComponentName(info.activityInfo.packageName,
                    info.activityInfo.name);
            final Intent intent = new Intent(Intent.ACTION_MAIN);
            intent.setComponent(component);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

            // launch app, and wait 7 seconds for it to start/settle
            getContext().startActivity(intent);
            try {
                Thread.sleep(7000);
            } catch (InterruptedException e) {
                // ignore
            }

            // See if there are any errors
            Collection<ProcessErrorStateInfo> procs = mActivityManager.getProcessesInErrorState();
            if (procs != null) {
                errSet.addAll(ProcessError.fromCollection(procs));
            }

            // Send the "home" intent and wait 2 seconds for us to get there
            getContext().startActivity(home);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                // ignore
            }
        }

        if (!errSet.isEmpty()) {
            fail(String.format("Got %d errors: %s", errSet.size(),
                    reportWrappedListContents(errSet)));
        }
    }

    private String reportWrappedListContents(Collection<ProcessError> errList) {
        List<ProcessErrorStateInfo> newList = new ArrayList<ProcessErrorStateInfo>(errList.size());
        for (ProcessError err : errList) {
            newList.add(err.info);
        }
        return reportListContents(newList);
    }

    /**
@@ -71,14 +152,14 @@ public class ProcessErrorsTest extends AndroidTestCase {
     * @param errList The error report containing one or more error records.
     * @return Returns a string containing all of the errors.
     */
    private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) {
    private String reportListContents(Collection<ProcessErrorStateInfo> errList) {
        if (errList == null) return null;

        StringBuilder builder = new StringBuilder();

        Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
        Iterator<ProcessErrorStateInfo> iter = errList.iterator();
        while (iter.hasNext()) {
            ActivityManager.ProcessErrorStateInfo entry = iter.next();
            ProcessErrorStateInfo entry = iter.next();

            String condition;
            switch (entry.condition) {
@@ -96,8 +177,77 @@ public class ProcessErrorsTest extends AndroidTestCase {
            builder.append("Process error ").append(condition).append(" ");
            builder.append(" ").append(entry.shortMsg);
            builder.append(" detected in ").append(entry.processName).append(" ").append(entry.tag);
            builder.append("\n");
        }
        return builder.toString();
    }

    /**
     * A {@link ProcessErrorStateInfo} wrapper class that hashes how we want (so that equivalent
     * crashes are considered equal).
     */
    private static class ProcessError {
        public final ProcessErrorStateInfo info;

        public ProcessError(ProcessErrorStateInfo newInfo) {
            info = newInfo;
        }

        public static Collection<ProcessError> fromCollection(Collection<ProcessErrorStateInfo> in)
                {
            List<ProcessError> out = new ArrayList<ProcessError>(in.size());
            for (ProcessErrorStateInfo info : in) {
                out.add(new ProcessError(info));
            }
            return out;
        }

        private boolean strEquals(String a, String b) {
            if ((a == null) && (b == null)) {
                return true;
            } else if ((a == null) || (b == null)) {
                return false;
            } else {
                return a.equals(b);
            }
        }

        @Override
        public boolean equals(Object other) {
            if (other == null) return false;
            if (!(other instanceof ProcessError)) return false;
            ProcessError peOther = (ProcessError) other;

            return (info.condition == peOther.info.condition)
                    && strEquals(info.longMsg, peOther.info.longMsg)
                    && (info.pid == peOther.info.pid)
                    && strEquals(info.processName, peOther.info.processName)
                    && strEquals(info.shortMsg, peOther.info.shortMsg)
                    && strEquals(info.stackTrace, peOther.info.stackTrace)
                    && strEquals(info.tag, peOther.info.tag)
                    && (info.uid == peOther.info.uid);
        }

        private int hash(Object obj) {
            if (obj == null) {
                return 13;
            } else {
                return obj.hashCode();
            }
        }

        @Override
        public int hashCode() {
            int code = 17;
            code += info.condition;
            code *= hash(info.longMsg);
            code += info.pid;
            code *= hash(info.processName);
            code *= hash(info.shortMsg);
            code *= hash(info.stackTrace);
            code *= hash(info.tag);
            code += info.uid;
            return code;
        }
    }
}
+12 −0
Original line number Diff line number Diff line
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := tests

LOCAL_SRC_FILES := $(call all-java-files-under, src)

LOCAL_PACKAGE_NAME := SmokeTestTriggerApps

include $(BUILD_PACKAGE)

include $(call all-makefiles-under,$(LOCAL_PATH))
+45 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2012 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.android.smoketest.triggers">

    <application android:label="something">
        <activity android:name=".CrashyApp"
                  android:label="Test Crashy App">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".CrashyApp2"
                  android:label="Test Crashy App2">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <activity android:name=".UnresponsiveApp"
                  android:label="Test Unresponsive App">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
+3 −0
Original line number Diff line number Diff line
The apps in this folder are intentionally bad-behaving apps that are intended
to trigger the smoke tests to fail.  They are otherwise not useful.
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
package com.android.smoketest.triggers;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class CrashyApp extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setText("Hello, Crashy Android");
        setContentView(tv);
    }

    @Override
    public void onResume() {
        ((String) null).length();
    }
}
Loading