第一部分 打印cts测试fail问题
[CTS][7.0r3][GMS][共有]进行CTS测试,CtsPrintTestCases—
android.print.cts.PrintJobTest#testStateTransitions—fai
gitclone gitadmin@gitsrv01.spreadtrum.com:android/platform/cts-b android-cts-7.0_r3
PrintActivity调用到 PrintJobTest中 call()过程。
1. 先从cts来看,基类 BasePrintTest,子类PrintJobTest
基类方法:
setUp():初始化信息,创建 启动PrintDocumentActivity。
clickPrintButton():
获取PrintActivity的 id/print_button按键,模拟点击。
waitForServiceOnPrintJobQueuedCallbackCalled(testCaseNum+ 1);等待60秒CallCounter 的call()被调用(调用条件重要),否则,超时失败。
子类方法:
baseTest():基础测试,初始化设置callBack及print(adapter)、clickPrintButton();
testStateTransitions():用建立的数组,双层循环打印状态,来调用baseTest()
2. PrintActivity类处理
当cts中模拟时,会调用clickPrintButton(),就会启动PrintActivity,并响应处理点击事件。
private ImageView mPrintButton;
mPrintButton = (ImageView)findViewById(R.id.print_button);
处理逻辑就是: confirmPrint() 或者cancelPrint()
正常情况下会确认打印调用。
confirmPrint方法主要更新ui状态及是否请求创建pdf文件或者finish调用。
第三行会打印对应log信息, 最后的判断很重要。
如果当前printer正确,会启动创建DocumentActivity. 否则,doFinish结束。
启动Intent.ACTION_CREATE_DOCUMENT对应的activity.
当PrintActivity调用以上时,会调用自己的onPause().会根据当前的状态去做对应处理,包括以下几种状态:
STATE_INITIALIZING
STATE_PRINT_COMPLETED
STATE_CREATE_FILE_FAILED
会依据状态调用:
PrintSpoolerService---setPrintJobState(PrintJobId printJobId, int state, String error)
当开始打印完成时,会设置打印任务状态,PrintJobInfo.STATE_QUEUED
3. PrintSpoolerService类处理
在setPrintJobState方法在,主要做以下几件事:
设置状态信息 printJob
log打印 MetricsLogger.histogram(this,"print_job_state", state);
是否删除打印任务文件 removePrintJobFileLocked(printJob.getId());
是否发送所以打印任务给服务
是否发送队列发送打印任务。
sendOnPrintJobQueued 发送打印任务
主要通过handler消息机制发送消息: MSG_ON_PRINT_JOB_QUEUED
HandlerCallerCallback的 executeMessage 执行接受消息。
客户端 AIDL方式: IPrintSpoolerClient 调用 onPrintJobQueued()
4. RemotePrintService远程客户端调用 onPrintJobQueued
onPrintJobQueued() 通过MyHandler.MSG_ON_PRINT_JOB_QUEUED消息发送;
接受后进行处理(当然也有许多其他情况,比如:取消、所有打印job等)
handleOnPrintJobQueued():
如果还没有绑定,用一个线程循环处理;否则,IPrintService 远程调用 :
mPrintService.onPrintJobQueued(printJob);
实际调用的是 PrintService的onBind()中绑定到IBinder的回调。
5. PrintService的处理
通过远程回调到该onPrintJobQueued方法发消息MSG_ON_PRINTJOB_QUEUED
继续调用PrintService的抽象方法:
protected abstract voidonPrintJobQueued(PrintJob printJob);
由于PrintService是一个抽象类,因此,必须有对应的实现类;
具体需要查找确认?
本问题是由cts测试,因此,是与cts相关的实现类。
public abstract class StubbablePrintServiceextends PrintService
6. StubbablePrintService的处理逻辑
这个类继承PrintService,并实现一些方法。
此处是通过PrintServiceCallbacks callbacks来回调的。查找确认,是由其他类继承该抽象类 StubbablePrintService,并复写该方法。
7. MockPrintServiceextends StubbablePrintService 处理逻辑
此类主要方法,一个静态setCallbacks设置CallBacks,另一个实现:
@Override
protected PrintServiceCallbacksgetCallbacks() {
synchronized (sLock) {
if (sCallbacks != null) {
sCallbacks.setService(this);
}
return sCallbacks;
}
}
8. 查找 MockPrintService的设置回调逻辑
FirstPrintService 与 SecondPrintService 两个服务。
这个要回归到 PrinteJobTest类中。
9. PrintJobTest类中callBack的初始化
这个初始化还是在 baseTest()处理的。
也就回归到 本文档开始部分的介绍。
可以知道FirstPrintService继承于 MockPrintService。
设置的对应回调对象是: PrintServiceCallbacks serviceCallbacks
此对象,是通过调用 PrintJobTest的 createFirstMockPrinterServiceCallbacks方法获得,重点是该方法的实现。
下面来研究下该方法获取callBack对象的实现:
入参包括:PrintJobTestFn printJobTest ,是一个接口类。
返回值是一个打印 Answer响应回调实现的 PrintServiceCallbacks对象。
因为,在StubbablePrintService中继承PrintService实现onPrintJobQueued(),
里面是通过callBack 调用callbacks.onPrintJobQueued(printJob);
因此,当PrintService调用onPrintJobQueued时,实际由对应的callBack去调用具体实现;此callBack就是上面的PrintServiceCallbacks对象。
该对象通过基类BasePrintTest中的createMockPrintServiceCallbacks()创建。
10. 基类 BasePrintTest的回调创建
这里看不出怎么回调onPrintJobQueued。
借助cts的log可以知道,是PrintServiceCallbacks_Proxy.onPrintJobQueued调用。
中间过程是 org.mockito.xx包中代码的处理,最后,调用到 PrintJobTest中
createFirstMockPrinterServiceCallbacks()创建时,Answer类中的answer()方法调用。
其中:
printJobTest.onPrintJobQueued(printJob); //
onPrintJobQueuedCalled(); //调用实现CallCounter.call()
参考如下log:
11. Cts测试问题分析
[CTS][7.0r3][GMS][共有]进
行CTS测试,CtsPrintTestCases--android.print.cts.PrintJobTest
#testStateTransitions--fai
分析: 此测试失败的根本原因在于cts测试时,在模拟找到打印按钮并启动PrintActivity界面后,正常去分发 onClick打印按钮事件,在按钮响应前(时间极短),由于 FusedPrintersProvider 检测到位置变化,会更新打印机,此时打印按钮响应后,会设置 mState状态值为2确认打印,在更新打印机执行后,会逐步调用,极短时间调用了PrintActivity.onPrinterAvailable,使mState状态值初始1,注意:确认打印和更新打印机都会调用 updateDocument(false)。
也就是RemotePrintDocument.java: update调用,更新打印界面的文档加载显示LayoutResultCallback.onLayoutFinished()调用handleOnLayoutFinished(),回调完成 mCommandResultCallback.onDone()去通知更新完成 notifyUpdateCompleted,
然后 (PrintActivity)mUpdateCallbacks.onUpdateCompleted()回调。
然后,在 PrintActivity中根据mState的值去相应处理,如果是2,则会最终调用到onPause(),将打印任务加入到队列:
spooler.setPrintJobState(mPrintJob.getId(),PrintJobInfo.STATE_QUEUED, null);
最终会在cts正常回调到call()+1操作,结束60秒等待;如果值是1,仅更新下打印界面UI视图,因此,不会调用到onPause()导致cts测试fail.
12. 更新打印机的原因 FusedPrintersProvider
此次失败,是因为位置变化更新了打印机。
如上代码,会根据检测到的location信息与当前的mLocation信息做对比,如果满足条件,会更新打印机。
如下log截图:
13. 总结分析
cts失败根本原因 是由于在测试是打印按钮点击时,位置发生变化,更新打印机状态(监听到位置变化时会更新打印机),将点击打印后的 2确认打印值 更新为1 初始配置,根据该值如果是2,会正常按照流程执行到 dofinish,调用onPasuse,由于被修改为1,导致状态不对fail。
失败cts测试的分析过程:
cts测试循环一次开始
A001-1311:32:19.247 24683 25510 I PrintJobTest: Test 3 -> 7 -> 3
// 启动打印界面
A001-1311:32:19.354 25570 25570 W PrintActivity: onCreate ...
// 位置信息
A001-1311:32:17.588 768 796 D LocationManagerService: incominglocation: Location[network 39.147421,117.389143 acc=50 et=+15h30m50s912ms
A001-1311:32:21.005 768 796 D LocationManagerService: incominglocation: Location[fused 39.147421,117.389143 acc=14 et=+15h30m54s362ms]
// 位置变化引起回调,onLoadFinished执行堆栈,会发消息调用onPrintersChanged
A001-1311:32:21.044 25570 25570 D xuehao : PrinterRegistry: onLoadFinished...start
A001-1311:32:21.044 25570 25570 D xuehao :java.lang.Exception
A001-1311:32:21.044 25570 25570 D xuehao : atcom.android.printspooler.ui.PrinterRegistry$1.onLoadFinished(PrinterRegistry.java:136)
A001-1311:32:21.044 25570 25570 D xuehao : atcom.android.printspooler.ui.PrinterRegistry$1.onLoadFinished(PrinterRegistry.java:134)
A001-1311:32:21.044 25570 25570 D xuehao : atandroid.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:486)
A001-1311:32:21.044 25570 25570 D xuehao : atandroid.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:454)
A001-1311:32:21.044 25570 25570 D xuehao : atandroid.content.Loader.deliverResult(Loader.java:144)
A001-1311:32:21.044 25570 25570 D xuehao : atcom.android.printspooler.ui.FusedPrintersProvider.computeAndDeliverResult(FusedPrintersProvider.java:248)
A001-1311:32:21.044 25570 25570 D xuehao : atcom.android.printspooler.ui.FusedPrintersProvider.updatePrinters(FusedPrintersProvider.java:368)
A001-1311:32:21.044 25570 25570 D xuehao : atcom.android.printspooler.ui.FusedPrintersProvider.onLocationChanged(FusedPrintersProvider.java:453)
A001-1311:32:21.044 25570 25570 D xuehao : atandroid.location.LocationManager$ListenerTransport._handleMessage(LocationManager.java:301)
A001-1311:32:21.044 25570 25570 D xuehao : at android.location.LocationManager$ListenerTransport.-wrap0(LocationManager.java)
A001-1311:32:21.044 25570 25570 D xuehao : atandroid.location.LocationManager$ListenerTransport$2.handleMessage(LocationManager.java:253)
/ 位置信息
A001-1311:32:21.048 768 796 D LocationManagerService: incominglocation: Location[fused 39.147421,117.389143 acc=14 et=+15h30m54s362ms]
A001-1311:32:21.055 768 796 D LocationManagerService: incominglocation: Location[network 39.147421,117.389143 acc=50 et=+15h30m54s362ms {Bundle[mParcelledData.dataSize=476]}]
// 打印按钮执行
A001-1311:32:21.068 25570 25570 I PrintActivity: MyClickListener ... onClick: mPrintButton
// 状态2表示确认打印,如果一直是此状态
A001-1311:32:21.074 25570 25570 I PrintActivity: [state]2
A001-1311:32:21.074 25570 25570 D xuehao :PrintActivity: confirmPrint start..
// 由于上面onPrintersChanged调用,调用onPrinterAvailable堆栈,该调用会设置打印状态为 1,导致fail
A001-1311:32:21.132 25570 25570 D xuehao : PrintActivity: onPrinterAvailable...
A001-1311:32:21.132 25570 25570 D xuehao : java.lang.Exception
A001-1311:32:21.132 25570 25570 D xuehao : atcom.android.printspooler.ui.PrintActivity.onPrinterAvailable(PrintActivity.java:2041)
A001-1311:32:21.132 25570 25570 D xuehao : atcom.android.printspooler.ui.PrintActivity$DestinationAdapter.onPrintersChanged(PrintActivity.java:2555)
A001-1311:32:21.132 25570 25570 D xuehao : atcom.android.printspooler.ui.PrinterRegistry$MyHandler.handleMessage(PrinterRegistry.java:180)
// 状态已经有2被位置改变最终修改为1,