监听Android CTS测试项解决方案(一)

前言:

首先这里需要详细叙述一下标题中”监听Android CTS测试项解决方案“的需求。这里的需求是指我们需要精确的监听到当前CTS测试正在测试的测试项。

因为我们知道CTS认证是获得Google推出的 Android 系统中 Android Market 服务的前提。CTS 兼容性测试的主要目的和意义在于使得用户在 Android 系统的应用过程中,有更好的用户体验,并展现出 Android
系统的优越特性;使得 Android 应用程序编写者更容易编写高质量的应用程序;充分展现 Android Market 的优势,让获得CTS认证的终端得到 Android Market 的使用许可。而我们在实际进行的CTS测试中并不是完全一帆风顺的,此时我们就需要掌握一些基本的CTS测试原理和流程。当然google已经开源了CTS Verifier测试工具的源码,从源码入手分析也是我们一个选择。

三思而后行,通过研究和分析这里提供两个方案(这里以Accelerometer Measurement Test测试项为例):

方案一:监听当前正在运行的Activity是否是Accelerometer Measurement Test测试项所处的Activity

方案二:监听当前测试项是否是Accelerometer Measurement Test测试项

一:监听当前正在运行的Activity是否为Accelerometer Measurement Test测试项所处的Activity

这种方式看起来已经跟CTS Verifier测试工具没有什么关系了,因为我们这里监听的是Activity,那么如何监听当前正在运行的Activity呢;从源码中并没发现谷歌提供该接口(至少是我没有找到)。那么我们知道Activity管理师通过task栈进行管理的,而且通过不同的启动方式,Activity的栈也不是唯一的。但是如果我们能够得到顶层栈中栈顶Activity则就可以检测到当前处于活动状态的Activity。

当然谷歌这里已经开放了相关接口,我们先认识一下:

            final ActivityManager am = (ActivityManager)mContext.getSystemService(Context.ACTIVITY_SERVICE);
            List<RunningTaskInfo> list = am.getRunningTasks(1);
            if (list.size() != 0) {
                RunningTaskInfo topRunningTask = list.get(0);
                ComponentName c= topRunningTask.topActivity;
                String packageName=c.getPackageName();
                String className=c.getClassName();
                android.util.Log.d("ComponentName","packageName-->"+packageName+"--className-->"+className);
            } 

从上面的代码中我们可以取到顶层栈中栈顶topActivity的信息,该信息被封装在ComponentName中。那么此时是不是完成了需求呢?

答案当然是否定的。

因为我们要时时刻刻监听栈顶Activity,才能确定当前活动的Activity是我们需要监听的Activity,因此除了能够得到栈顶的Activity我们还需要监听Activity的切换,但是此时Android原生代码中并没有提供相关的接口,这个时候有人会想到可以使用线程或者服务反复的去判断栈顶Activity是否已经发生变化。当然这样是不可取的,因为我们还要考虑到该线程或者服务不会被系统回收。因此我们该如何去监听Activity的切换呢?

我们知道,Activity的切换无非有两种,第一种:启动或者创建一个新的Activity;第二种:唤醒后台运行的Activity。因此如果我们能够成功监听到启动或者创建一个Activity,或者唤醒Activity我们就基本完成了Activity的切换的监听。

在源码/frameworks/base/core/java/android/app目录下ActivityThread.java中为我们提供了这样一个方法来帮助我们完成对Activity启动、创建、销毁、暂停、停止,唤醒等生命周期的监听。

public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    /// M: enable profiling @{
                    if ( true == mEnableAppLaunchLog && !mIsUserBuild && false == mTraceEnabled ) {
                        try {
                            FileInputStream fprofsts_in = new FileInputStream("/proc/mtprof/status");
                            if ( fprofsts_in.read()== '3' ) {
                                Log.v(TAG, "start Profiling for empty process");
                                mTraceEnabled = true;
                                Debug.startMethodTracing("/data/data/applaunch"); //applaunch.trace
                            }
                        } catch (FileNotFoundException e) {
                            Slog.e(TAG, "mtprof entry can not be found", e);
                        } catch (java.io.IOException e) {
                            Slog.e(TAG, "mtprof entry open failed", e);
                        }
                    }
                    /// @}
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER | Trace.TRACE_TAG_PERF, "activityStart"); /// M: add TRACE_TAG_PERF for performance debug
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER | Trace.TRACE_TAG_PERF); /// M: add TRACE_TAG_PERF for performance debug
                } break;
                case RELAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                    handleRelaunchActivity(r);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                case PAUSE_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, false, msg.arg1 != 0, msg.arg2);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PAUSE_ACTIVITY_FINISHING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
                    handlePauseActivity((IBinder)msg.obj, true, msg.arg1 != 0, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_ACTIVITY_SHOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    handleStopActivity((IBinder)msg.obj, true, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_ACTIVITY_HIDE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");
                    handleStopActivity((IBinder)msg.obj, false, msg.arg2);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SHOW_WINDOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");
                    handleWindowVisibility((IBinder)msg.obj, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case HIDE_WINDOW:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");
                    handleWindowVisibility((IBinder)msg.obj, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case RESUME_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER | Trace.TRACE_TAG_PERF, "activityResume"); /// M: add TRACE_TAG_PERF for performance debug
                    handleResumeActivity((IBinder)msg.obj, true,
                            msg.arg1 != 0, true);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER | Trace.TRACE_TAG_PERF); /// M: add TRACE_TAG_PERF for performance debug
                    break;
                case SEND_RESULT:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");
                    handleSendResult((ResultData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case DESTROY_ACTIVITY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");
                    handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,
                            msg.arg2, false);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case BIND_APPLICATION:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
                    AppBindData data = (AppBindData)msg.obj;
                    handleBindApplication(data);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case EXIT_APPLICATION:
                    if (mInitialApplication != null) {
                        mInitialApplication.onTerminate();
                    }
                    Looper.myLooper().quit();
                    break;
                case NEW_INTENT:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityNewIntent");
                    handleNewIntent((NewIntentData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case RECEIVER:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveComp");
                    handleReceiver((ReceiverData)msg.obj);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceCreate");
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case BIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind");
                    handleBindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case UNBIND_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
                    handleUnbindService((BindServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SERVICE_ARGS:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStart");
                    handleServiceArgs((ServiceArgsData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case STOP_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceStop");
                    handleStopService((IBinder)msg.obj);
                    maybeSnapshot();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case REQUEST_THUMBNAIL:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "requestThumbnail");
                    handleRequestThumbnail((IBinder)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case CONFIGURATION_CHANGED:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "configChanged");
                    mCurDefaultDisplayDpi = ((Configuration)msg.obj).densityDpi;
                    handleConfigurationChanged((Configuration)msg.obj, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case CLEAN_UP_CONTEXT:
                    ContextCleanupInfo cci = (ContextCleanupInfo)msg.obj;
                    cci.context.performFinalCleanup(cci.who, cci.what);
                    break;
                case GC_WHEN_IDLE:
                    scheduleGcIdler();
                    break;
                case DUMP_SERVICE:
                    handleDumpService((DumpComponentInfo)msg.obj);
                    break;
                case LOW_MEMORY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "lowMemory");
                    handleLowMemory();
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case ACTIVITY_CONFIGURATION_CHANGED:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityConfigChanged");
                    handleActivityConfigurationChanged((IBinder)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case PROFILER_CONTROL:
                    handleProfilerControl(msg.arg1 != 0, (ProfilerControlData)msg.obj, msg.arg2);
                    break;
                case CREATE_BACKUP_AGENT:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupCreateAgent");
                    handleCreateBackupAgent((CreateBackupAgentData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case DESTROY_BACKUP_AGENT:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "backupDestroyAgent");
                    handleDestroyBackupAgent((CreateBackupAgentData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SUICIDE:
                    Process.killProcess(Process.myPid());
                    break;
                case REMOVE_PROVIDER:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "providerRemove");
                    completeRemoveProvider((ProviderRefCount)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case ENABLE_JIT:
                    ensureJitEnabled();
                    break;
                case DISPATCH_PACKAGE_BROADCAST:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastPackage");
                    handleDispatchPackageBroadcast(msg.arg1, (String[])msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SCHEDULE_CRASH:
                    throw new RemoteServiceException((String)msg.obj);
                case DUMP_HEAP:
                    handleDumpHeap(msg.arg1 != 0, (DumpHeapData)msg.obj);
                    break;
                case DUMP_ACTIVITY:
                    handleDumpActivity((DumpComponentInfo)msg.obj);
                    break;
                case DUMP_PROVIDER:
                    handleDumpProvider((DumpComponentInfo)msg.obj);
                    break;
                case SLEEPING:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "sleeping");
                    handleSleeping((IBinder)msg.obj, msg.arg1 != 0);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case SET_CORE_SETTINGS:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "setCoreSettings");
                    handleSetCoreSettings((Bundle) msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case UPDATE_PACKAGE_COMPATIBILITY_INFO:
                    handleUpdatePackageCompatibilityInfo((UpdateCompatibilityData)msg.obj);
                    break;
                case TRIM_MEMORY:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
                    handleTrimMemory(msg.arg1);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                case UNSTABLE_PROVIDER_DIED:
                    handleUnstableProviderDied((IBinder)msg.obj, false);
                    break;
                case REQUEST_ASSIST_CONTEXT_EXTRAS:
                    handleRequestAssistContextExtras((RequestAssistContextExtras)msg.obj);
                    break;
                case TRANSLUCENT_CONVERSION_COMPLETE:
                    handleTranslucentConversionComplete((IBinder)msg.obj, msg.arg1 == 1);
                    break;
                case INSTALL_PROVIDER:
                    handleInstallProvider((ProviderInfo) msg.obj);
                    break;
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
            /// M: ActivityThread log enhancement @{
            if(!mIsUserBuild && isDebuggableMessage(msg.what)){
                Slog.d(TAG, codeToString(msg.what) + " handled "
                + ": " + msg.arg1 + " / " + msg.obj);
            }
            /// @}
        }

这里我们可以看到,我们可以通过监听LAUNCH_ACTIVITY和RESUME_ACTIVITY来判断Activity的切换,因此我们可以将通过在ActivityThread.java中将获得顶层栈栈顶Activity的方法在这里调用以实现我们的需求。

那么这样是否能够完成我们的需求呢?

答案依旧是否定的。即使我们能够编译通过,但是在我们测试观察log的时候,并不能得到当前处于活动状态的Activity。那么为什么会出现这种情况呢?

通过观察log我们发现,这里我们需要GET_TASK权限,当然我们可以通过添加权限的方式,但这样有风险,那么有没有一个更可靠的方式呢。

依旧是通过观察log,我们发现Android系统会使用一个ActivityClientRecoder类来记录Activity的信息,而这个类在ActivityThread中也得到了应用,因此我们可以通过得到ActivityClientRecoder的对象r来获得Activity对象,在通过Activity对象的getComponent()来得到ComponentName的对象,在ComponentName对象中便封装了应用程序包名和当前处于活动状态的Activity。

具体实现方式这里不再赘述。

此外还有一种备用的方式,就是我们可以通过得到当前处于活动状态进程信息来判断当前处以活动状态的进程。

实现方式如下:

        final ActivityManager am = (ActivityManager)mAppContextImpl.getSystemService(Context.ACTIVITY_SERVICE);
        List<RunningAppProcessInfo> list = am.getRunningAppProcesses();

        if (list.size() != 0) {
            RunningAppProcessInfo topRunningProcess = list.get(0);
            if(topRunningProcess.processName.equals("com.android.xx.xxxxx")){
                return true;
            }
        }
        return false;

注意!

我们如何得到我们需要判断的那个Activity的名字呢,当然如果那个Activity是你开发定义的就无所谓了,如果不是,或者是第三方的APK,也没关系,google提供了一个工具可以对apk进行反编译,因此我们可以从反编译的AndroidManifest.xml文件中得到相关Activity的name。

时间: 2024-10-14 12:10:06

监听Android CTS测试项解决方案(一)的相关文章

监听Android CTS测试项解决方案(二)

二,监听当前测试项是否是Accelerometer Measurement Test测试项 通过第一种方式介绍的,我们可以得到当前处于活动状态的Activity类似监听CTS测试当前的测试项.但是由于是监听Android系统中所有Activity,因此会大大降低系统的性能,因此这里有一种效率更高的方式来精确定位当前CTS正在测试的测试项,而不会对系统造成很大的影响.(当然不能修改CTS源码,我们需要使用Android提供的原生CTS APK进行验证) 那么我们这里以Accelerometer M

服务器重启后Oracle监听服务没有自动启动的解决方案

最近一直在被这样一个问题烦恼,就是服务器断电重启后,Oracle监听服务没有正常自动启动(监听服务已经设置为自启动). 具体是这样的,监听服务设置为开机自启动,Oracle数据库服务设置为开机延时启动,按道理这个应该符合“先启动监听,后启动数据库服务”这个条件,但是每次断电重启后都是数据库服务正常启动了,监听服务没能启动. 查阅了一下,有这么两个说法,感觉还是挺有道理: 1.一般设置了开机自启动的服务要手动,基本是注册表不一致造成: 2.登录账号跟你安装Oracle的账号不一样,没权限启动. 针

Android 监听 Android中监听系统网络连接打开或者关闭的实现代码

本篇文章对Android中监听系统网络连接打开或者关闭的实现用实例进行了介绍.需要的朋友参考下 很简单,所以直接看代码 复制代码 代码如下: package xxx; import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.Intent;  import android.net.ConnectivityManager;  import android.ne

Android监听Home键的完美解决方案

相信有不少朋友在开发过程中需要监听HOME键的需求,现本人将代码奉上,希望对大家有所帮助! import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; public class HomeWatcher { private static final String TAG = "

Android CTS测试

一什么是CTS CTS简介:Compatibility Test suite系列兼容测试 google定义了一个兼容性规范(Compatible Definition),而CTS就是为了确保某个测试符合该规范.从而基于Android的应用程序能在基于同一个api版本的设备上面运行.通过CTS测试的device可以获得android的商标,并且享受android market的权限. 例如手机.平板电脑.车载娱乐系统:严格来说需要下载第三方应用的Android系统都要通过CTS测试,才能达到兼容性

【Android代码片段之八】监听Android屏幕是否锁屏

实现方法:1)通过BroadcastReceiver接收广播Intent.ACTION_SCREEN_ON和Intent.ACTION_SCREEN_OFF可以判断屏幕状态是否锁屏,但是只有屏幕状态发生改变时才会发出广播: 2)如果要在屏幕状态发生改变之前就想获取屏幕状态,可以通过反射机制调用PowerManager的isScreenOn方法 . 具体实现,见代码: 实现Screen状态监听的类ScreenObserver,实现如下: [java] view plaincopy package 

从网页监听Android设备的返回键

最近搞Android项目的时候,遇到一个比较蛋疼的需求,需要从Client App调用系统浏览器打开一个页面,进行杂七杂八的一些交互之后,返回到App.如何打开浏览器和如何返回App这里就不说了,有兴趣的童鞋可私下交流. 之所以说这个需求蛋疼,是因为Android有个物理返回键啊……返回键啊……键啊……啊…… 用户按下返回键后,预期应该跟点击页面上的返回键一样——返回App.然而这个返回键的被按下的时候网页完全不知道啊(onbeforeunload不算),找不到直接的办法去监听,愁死我们这全苦逼

关于动态监听的一些测试

昨天做了一个实验,环境是这样的,建立一个静态监听端口1526以及一个动态监听端口1521,并且要通过在tnsname用两种连接字符串进行连接,静态连接的字符串直接连接没有问题,可是后来动态连接的字符串怎么也连接不进去,尝试注册 SQL> alter system register; System altered. [[email protected] ~]$ lsnrctl stat LSNRCTL for Linux: Version 11.2.0.1.0 - Production on 26

监听Android的Home键碰到的问题

Android的TV监听Home键切换信源碰到的问题 实现的功能是按下Home键,焦点放到TV小窗口上,再次按下Home键,切换信源,进入另一个信源.在另一个信源的显示下,按下Home键,原信源视图缩小并显示当前信源. 这个需求的解决代码比较容易的.实现一个BroadCastReceiver,监听Home键.但是依照HOME键的实现的时候,系统会切换到当前Launcher,因此,在当前信源的情况下点击HOME键,走的流程是: onPause->onStop->onRestart->onS