CSDN blog recommended article Http://prog3.com/sbdm/blog Http://prog3.com/sbdm/static.blog/images/logo.gif CSDN blog content aggregation service Http://prog3.com/sbdm/blog Zh-cn (C) 2011 PROG3.COM Http://prog3.com/sbdm/blog 10:53:13 2015/12/8 Android: inter process communication Http://prog3.com/sbdm/blog/bdmh/article/details/50206737 Http://prog3.com/sbdm/blog/bdmh/article/details/50206737 Bdmh 10:04:50 2015/12/8

ComponentName Intent

Intent as our most commonly used data transmission channels, especially through the Intent to open a Activity, presumably everyone will not be unfamiliar. Usually we use Intent to open the same process (App) internal Activity, if you want to achieve cross process communication, you need to send the Intent object to another (App), and parse out, then you need ComponentName to do this thing for us. Since you can send data to another process, you can also achieve the interaction between different processes.
Note: if the A is to open up the Activity in the B in the other process, then the Activity file in the AndroidManifest project will be opened for exported, which will be true, otherwise it will be reported.

Android:Exported="True"

We will use the ComponentName constructor as follows:

    Public ComponentName(PKG String, CLS String) {
        If(PKG = =Null)Throw NewNullPointerException ("Name is null package");
        If(CLS = =Null)Throw NewNullPointerException ("Name is null class");
MPackage = pkg;
MClass = cls;
}

It takes two parameters, the first parameter is a pakage (package), and the second is the name of the class you want to open:
Process AndroidAIDL (com.example.androidaidl) in the MainActivity

    @Override
    Protected Void OnCreate(savedInstanceState Bundle) {
        Super.onCreate (savedInstanceState);
SetContentView (R.layout.activity_main);
        Receive / pass Intent
        If(getIntent ()!Null{)
System.out.println ("--"+getIntent ().GetIntExtra"Id",0+)"--");
}
}

Another process AndroidTest, where we write the following code in MainActivity:

Specify the package name and / * * with the package name the name of the Activity.
ComponentName ComponentName =NewComponentName ("Com.example.androidaidl","Com.example.androidaidl.MainActivity");
Intent Intent =NewIntent ();
Intent.putExtra ("Id",1001);
Intent.setComponent (componentName);
StartActivity (intent);

After running the above code, you will see the LogCat printing 1001, indicating that the AndroidTest process to receive the Intent normal.

Note: the above code we pass the basic data types, for the basic data types, such as Int, String, such as receiving the above can be read directly, but if the transmission is a complex object, the object needs to achieve Serializable or Parcelable interface.
For example, we define a SendData object as the delivery object, which implements the Parcelable interface:

Public Class SendData Implements Parcelable{
    IntId;
Content String;
    Public Int GetId(1)
        ReturnId;
}
    Public Void SetId(IntID) {
        This.id = id;
}
    PublicStringGetContent(1)
        ReturnContent;
}
    Public Void SetContent(content String) {
        This.content = content;
}
    Public Static FinalCREATOR Parcelable.Creator<SendData> =NewParcelable.Creator<SendData> () {

        @Override
        PublicSendDataCreateFromParcel(source Parcel) {
            Auto-generated method stub / / TODO
Data SendData =NewSendData ();
Data.setId (source.readInt ());
Data.setContent (source.readString ());
            ReturnData;
}

        @Override
        PublicSendData[]NewArray(IntSize) {
            Auto-generated method stub / / TODO
            Return NewSendData[size];
}

};

    @Override
    Public Int DescribeContents(1)
        Auto-generated method stub / / TODO
        Return 0;
}

    @Override
    Public Void WriteToParcel(dest Parcel,IntFlags) {
        Auto-generated method stub / / TODO
Dest.writeInt (ID);
Dest.writeString (content);
}

}

Send code:

Intent Intent= NewIntent ();
SendDataData = NewSendData ();
Data.(setId1001);
Data.SetContent ("World hellow");
Send / / serialized objects
Intent.PutExtra ("Data",Data);
StartActivity (intent);

Receive code

受保护的 无效 onCreate(束savedinstancestate){
超级onCreate(savedinstancestate);
setContentView(r.layout。activity_main);
    如果(getintent()!=){
        如果(getintent() getparcelableextra(。“数据”)= =返回/ /读取序列化对象,并转化为发送类型
发送数据(发送数据)getintent() getparcelableextra(。“数据”);
系统。println(。“----------”getcontent() + +数据。“-----------”);
}
}

如果在同一个进程的话,上面的方法没有任何问题,如果在不同进程中,就要注意,发送数据时,这个豆所在的包名,在各个项目中必须一样,否则接收方,无法解析

广播- BroadcastReceiver

Android的广播是系统级的,只要传递的行动一样(下面的例子中,都使用action_test),就可以接收到其他进程广播的消息,广播中可以通过意图传递数据。

发送方代码:

意图意图= 新的意图(“action_test”);
发送数据数据 = 新的senddata();
数据压缩文件SetID(1001);
数据setContent(“你好世界”);
意图putExtra(“数据”数据);
意图putExtra(“身份证”1001);
getactivity()sendBroadcast(意图);

接收方代码(动态注册广播):

innerreceiver =新的innerreceiver();
IntentFilter过滤=新的IntentFilter(“action_test”);
代码注册广播接收器(innerreceiver,过滤);

等级 innerreceiver 延伸 BroadcastReceiver{

“重写”
    公共 无效OnReceive(语境、意图意图){
        / /待办事项自动生成方法存根
        如果(意图。getaction()。等于(“action_test”){
发送数据(发送数据)的意图。getparcelableextra(“数据”);
系统,println(。“-----------”getcontent() + +数据。“------------”);
}
}
}

因为是通过意图传递数据,所以对复杂对象的要求和第一种方式一样,要求豆所在的包名一样

内容提供者

通常用来操作数据集ContentProvider,Android本身就提供了不少的ContentProvider访问,比如联系人、相册等。
访问ContentProvider,需要通过URI,需要以”内容:/ /”开头。下面看看使用方法:
在进程androidaidl(COM。例子。androidaidl),我们定义一个继承自ContentProvider的类,需要重载它的方法,这里我们以查询为例

公共 等级 providertest 延伸 内容提供者{
    私人 静态 最后urimatcher匹配=新的urimatcher(
urimatcher no_match);
    静态{
    / /添加访问字符串,对应配置文件中的Android:当局属性
adduri(匹配。“COM。MH。GetData”“股票”10001);
}

    “重写”
    公共 布尔 onCreate(){
        / /待办事项自动生成方法存根
        返回 ;
}

    “重写”
    * * * *
*@参数路径URI的URI
*@参数投影要保护的列集合,如果传空,所有列都会被包含进去。
*@参数选择用来过滤数据集的规则,空表示不筛选。
*@参数类似字符串的格式化在selection中,选择参数中可以包含?S,这个将被在selection中的内容替换
*@参数排序顺序。
*
    公共光标查询(URI URI字符串[]投影,字符串的选择,
[ ]在selection中的字符串,字符串的排序){
        / /待办事项自动生成方法存根
系统,println(。“--------------------查询----------------------”);
        返回 ;
}

    “重写”
    公共字符串方法(URI的URI){
        / /待办事项自动生成方法存根
        返回 ;
}

    “重写”
    公共URI插入(URI的URI,内容值){
        / /待办事项自动生成方法存根
        返回 ;
}

    “重写”
    公共 国际的 删除(URI的URI字符串,字符串的选择,[ ]在selection中){
        / /待办事项自动生成方法存根
        返回 0;
}

    “重写”
    公共 国际的 更新(URI的URI字符串值,内容,选择,
字符串在selection中[ ]){
        / /待办事项自动生成方法存根
        返回 0;
}

}

定义了这个类后,需要在AndroidManifest.xml对它进行声明,安卓:输出=真实,记得要写,否则会提示权限错误

        <供应商 安卓:名字=“providertest” 安卓系统=“COM。MH。GetData”
            安卓:出口=“真”>            
        < /供应商>

上面的配置有两个属性
安卓:名字就是类名成
Android:authorities this is the front of the Uri, the outside need to access the Provider

Here's a look at the caller, in another process, we have the following code:

Resolver ContentResolver = getActivity ().GetContentResolver ();
Uri * added /**com.mh.getdata/stock and Provider to the process
URI Uri = Uri.parse ("Content://com.mh.getdata/stock");
Cursor Cursor = resolver.query (uri,Null,Null,Null,Null);

After calling the above code, LogCat in print out "query" word, table name Provider call successfully, we can through resolver and AndroidAIDL process in the Provider object to interact.

AIDL

An interface definition language, Android will automatically generate communication code, through the AIDL we can in a process, call the other process of the method, it is said that some of the company's Service is to kill the AIDL is through the to protect live, can be a good study. Personally think that AIDL is more suitable to do plug-in system, or a number of app to form a system, such as WebView because of memory leakage is more serious, so some companies will be a separate WebView app, a separate call, then we through AIDL technology, you can call this app interface, to operate WebView behavior.
The use method is introduced here:
In two projectsThe new file (Eclipse ->General->File new), remember to write on the suffix name (Aidl), the two items in the file where the package name to remain consistent, the content is also the same, such as figure

Here to write a picture description
After the compiler, will be in the gen directory, automatically generate the same name, the suffix for the Java file. There are the Stub class that we need to use.

Public Static Abstract Class Stub Extends Android.OS.Binder Implements COM.Example.Aidl.AidlFunctions

In the interface file AIDLFunctions.aidl, we define a method show

Interface AidlFunctions{
    VoidShow ();
}

Server:
AIDL use, need a Service with, so we have to declare a Service

Public Class AIDLService Extends Service{
//stub is automatically generated by the system.
Binder AidlFunctions.Stub;

    @Override
    Public Void OnCreate(1)
        Auto-generated method stub / / TODO
        Super.onCreate ();
}

    @Override
    PublicIBinderOnBind(intent Intent) {
        Auto-generated method stub / / TODO
Binder =NewAidlFunctions.Stub () {

            @Override
            Here is our implementation / statement on the interface of the
            Public Void Show()ThrowsRemoteException {
                Auto-generated method stub / / TODO
System.out.println ("Than from conducting");
}
};
        ReturnBinder;
}
}

In AndroidManifest statement Service

        <Service Android:name="Com.example.androidaidl.AIDLService">
            <Intent-filter>
                <Action Android:name="Com.example.androidaidl.AIDLService">
            < /Intent-filter>
        < /Service>

Client:

/ / bound service to use ServiceConnection
PrivateServiceConnection ServiceConnection;
/ / a custom interface, and the server.
PrivateAidlFunctions AidlFunctions;

ServiceConnection =NewServiceConnection () {

@Override
    Public Void OnServiceDisconnected(name ComponentName) {
        Auto-generated method stub / / TODO
System.Out.println ("--------------------ServiceDisconnected----------------------");
}

@Override
    Public Void OnServiceConnected(name IBinder, service ComponentName) {
        Auto-generated method stub / / TODO
System.Out.println ("--------------------ServiceConnected----------------------");
AidlFunctions = AidlFunctions.Stub.asInterface (service);
}
};
Intent Intent =NewIntent ("Com.example.androidaidl.AIDLService");
BindService (intent, serviceConnection, Context.BIND_AUTO_CREATE);
/ / call the show method
Try{
AidlFunctions.show ();
}Catch(E RemoteException) {
    Auto-generated catch block / / TODO
E.printStackTrace ();
}
Author: bdmh was published in 10:04:50 2015/12/8Original link
Read: 89 comments: 0View comments
]]>
Mongodb driver c# insert duplicate records Http://prog3.com/sbdm/blog/lan_liang/article/details/50214897 Http://prog3.com/sbdm/blog/lan_liang/article/details/50214897 Csharp25 9:53:47 2015/12/8
In the use of MongoDB, sometimes you need to add an identical record to DB, if you use
Update<T>.AddToSet (x = x.objects, new T (T))


You don't work, because the AddToSet will judge whether the inserted record already exists.


Therefore need to use:
Update<T>.Push (x = x.objects, new T (T))

Specific discussions can be seen:

Http://stackoverflow.com/questions/27248556/mongodb-difference-between-push-addtoset


Official documents:
Https://docs.mongodb.org/manual/reference/operator/update/push/
Https://docs.mongodb.org/manual/reference/operator/update/addToSet/

Author: csharp25 was published in 9:53:47 2015/12/8Original link
Read: 102 comments: 0View comments
]]>
QT using quick sort Http://prog3.com/sbdm/blog/u013007900/article/details/50214869 Http://prog3.com/sbdm/blog/u013007900/article/details/50214869 U013007900 9:49:36 2015/12/8 Today I thought of using QT to do a quick sort, so the study.
Because of the use of the habit, std: C++: sort, even if it is C stdlib.h in qsort.

Handwriting board
The fast line is not difficult to write, but since the use of C++ to hit the ACM after a few naked knock.

C language stdlib
Power: use quick sort routines for sorting
Using method: qsort void (voidBase, nelem int, width int, int (*fcmp) (void constVoid const *);
Parameters:
1 the first address of the array to be sorted
2 array elements to be sorted
3 the occupancy of each element
4 pointer to a function to determine the order of the order.
This library function is supported in QT, but I do not use this thing now, and this function is not supported by the STL sort.

Then use the standard library, "algorithm" sort "QT", which is a special sort of C++, but can't be identified in sort, std:: sort. In fact, you can understand the String into QString, so we guess is qSort.
Usage and sort almost.

Header: < Namespace: STD algorithm>

BoolCapitySort(constSVideoChipConst, msVideoFirstSVideoChipMsVideoSecond)
{
    Return(msVideoFirst.mi64VideoCapacity < msVideoSecond.mi64VideoCapacity);
}

* voidVideoSort(QList<SVideoChip>* msVideoChipList)
{
QSort (msVideoChipList->Begin(), msVideoChipList->End(),CapitySort);
   / / Std:: sort(msVideoChipList->Begin(), msVideoChipList->End(),CapitySort);
}
Author: u013007900 was published in 9:49:36 2015/12/8Original link
Read: 96 comments: 0View comments
]]>
Design a thread safe single case (Singleton) mode Http://prog3.com/sbdm/blog/gggg_ggg/article/details/50214245 Http://prog3.com/sbdm/blog/gggg_ggg/article/details/50214245 Gggg_ggg 9:43:23 2015/12/8 In the design of a single model, although it is easy to design a class type, but taking into account the garbage collection mechanism and thread safety, we need to think more. Some designs may be forced to meet the requirements of the project, but in the design of multi thread. Do not consider the thread safety, will give us the program design risks. Here, we do not introduce what is a single model, it does not introduce how to design a simple design pattern, because you can be in the book or in the blog to find. Our aim here is to design a single example of the use of a model. One example of a model requires attention and Thinking:

(1) how can an object be simply an object?

(2) how to design the garbage collection mechanism?

(3) how to ensure thread safety?

In several of these problems considered. First of all, the design of a thread safe class, note: due to the CResGuard classes will be multiple threads to access, so this class in addition to the constructor and destructor accident, other members are thread safe.

CResGuard class {
Public:
CResGuard () {m_lGrdCnt = 0; InitializeCriticalSection (&m_cs);}
~CResGuard () {DeleteCriticalSection (&m_cs);}

/ / IsGuarded for debugging
IsGuarded const () BOOL {return (m_lGrdCnt > 0);}

Public:
CGuard class {
Public:
CGuard (RG CResGuard&): m_rg (RG) {m_rg.Guard ();};
~CGuard () {m_rg.Unguard ();}

Private:
M_rg CResGuard&;
};

Private:
Guard void () {EnterCriticalSection (&m_cs); m_lGrdCnt++;}
Unguard void () {m_lGrdCnt--; LeaveCriticalSection (&m_cs);}

Only two Guard/Unguard / / CGuard access method is embedded.
Class CResGuard: friend: CGuard;

Private:
M_cs CRITICAL_SECTION;
M_lGrdCnt long;
};


Next we need to design a class that meets the above three conditions. In order to realize the automatic recovery mechanism, we use the smart pointer auto_ptr, although many people do not like it, because the use of improper, will generate a lot of traps, so you can use other smart pointer to replace it. In order to facilitate the future use, also used the template, if you don't like, can take two minutes to get rid of it easily.

Pattern namespace
{
<class T> template
Singleton class
{
Public:
Inline T* instance static ();

Private:
Singleton (void) {}
~Singleton (void) {}
Singleton (const Singleton&) {}
Singleton & operator= (const & Singleton) {}

Auto_ptr<T> _instance static;
CResGuard _rs static;
};

<class T> template
Singleton<T> auto_ptr<T>:: _instance;

<class T> template
Singleton<T> CResGuard:: _rs;

<class T> template
T* Singleton<T> inline:: instance ()
{
(0) (if = _instance.get)
{
CResGuard:: GD CGuard (_rs);
(0) (if = _instance.get)
{
_instance.reset (T new);
}
}
_instance.get return ();
}
/ / implement the singleton class, must be placed in the macro definition declaration,
DECLARE_SINGLETON_CLASS #define (type) \
Class auto_ptr< type friend >
Class Singleton< type friend >;
}

Single case we although seemingly simple, but too much problem is worth thinking about and get to the bottom, because to a certain extent, it deep into the C + + language mechanism, can deepen your this design language comprehension.

Author: gggg_ggg was published in 9:43:23 2015/12/8Original link
Read: 98 comments: 0View comments
]]>
The 2 chapter of the fourteenth section "MonkeyRunner source analysis" HierarchyViewer implementation principle of -HierarchyViewer Architecture Overview Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212879 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212879 Zhubaitian 9:18:28 2015/12/8 The introduction of the HierarchyViewer library allows the MonkeyRunner to be written in the way of the control. What is the principle of its implementation? In this section we begin to begin to unveil the mystery of it.

The work of the framework of the HierarchyViewer requires the collaboration of ViewServer, which is based on the CS (Client-Server) architecture. In the last chapter, we have learned how to make a ViewServer for the Server to provide access control list of services, then this chapter we mainly analysis is done for the HierarchyViewer side of the Client is how to achieve the ViewServer server to get the control list and other related work.

From the point of view of our MonkeyRunner test script, we generally use HierarchyViewer:

1 device = MonkeyRunner.waitForConnection ()
2 viewer = device.getHierarchyViewer ()
3 view = viewer.findViewById ("id/button") a ViewNode #Return
4 P = viewer.getAbsoluteCenterOfView (view)
5 device.touch (p.x, p.y, MonkeyDevice.DOWN_AND_UP)
Code 14-2-1 click through the control button

From the above code we can see that the entire HierarchyViewer process is very simple and straightforward:

  • The first step is to obtain an instance of HierarchyViewer by MonkeyDevice.
  • The second step: use the instance of HierarchyViewer to obtain a ViewNode instance of the control by using the ID to control the
  • The third step: in the end, you can expose the various control properties through the operation of the ViewNode instance to control the operation of the

We end up with the ViewNode control instance of the property to operate the control is really let us use it handy, but hidden in these simple script code behind the realization of the principle is not so simple. We try to give out the questions in our heads:

  • Question findViewById 1: is the control that we need to get from the control ID? Directly to the ViewServer ID let it go to find it? Or by other means?
  • Question 2: what is the getHierarchyViewer MonkeyDevice method to do?

The answer to these two questions is the focus of this chapter, we first take these two questions to study, and finally the problem will be self-evident.

Next we look at the key class of the class diagram to understand the next HierarchyViewer:


Figure HierarchyViewer 11-2-1 class diagram

From the above we can see the entire framework is actually involved in a number of libraries, including chimpchat, hierarchyviewerlib and ddmlib class, where the first brief description of the main use of each library, as well as these classes are here the main role, in fact, many of us have been in contact with the previous chapter, but it has not been possible to describe what these classes are related to HierarchyViewer.


The class name

Library

Effect

Notes

HierarchyViewer

Chimpchat

Provide control relatedAPICall to test developers, such asFindViewByIdEtc.

HaveDdmlibTheDeviceAn instance of the class, so it can be operated by the instance.AdbHelperWithADBServer communication

Device

Ddmlib

The main role here is to call directlyAdbHelperFromADBServer send command


AdbHelper

Ddmlib

Responsible connectionADBServer and send commands to it


DeviceBridge

Hierarchyviewerlib

Equivalent toViewServerIn the client agent, the relationship is similar to that of theAdbdAndADBServer relationship;

Command and then callDeviceConnectionTheAPISend commands toViewServer

DeviceConnection

Hierarchyviewerlib

ConnectViewServerTheSocketClient, specifically for connectionViewServer,Send command and receive command to return


Window

Hierarchyviewerlib

Represents a control's window, it follows the controlViewNodeIs not the same, it will not save all the properties of the control, its main member variables are: window titleMTitle;Represents the hash value of the window


ViewNode

Hierarchyviewerlib

Represents a control, withWindowInstance and all property information for a control



Table HierarchyViewer 11-2-1 key classes

Next we describe how each class is interacting:

  • HierarchyViewer dependent DeviceBridge: setupViewServer will call the HierarchyViewer method to prepare the target machine end of the ViewServer during initialization. The DeviceBridge is called a series of methods to accomplish these things, in which the DeviceBridge is a static class.
  • DeviceBridge dependent DeviceConnection: the DeviceBridge member method will initialize the DeviceConnection object to send to the ViewServer, such as the DUMP command, through the organization of the organization.
  • DeviceBridge dependent ViewNodeDeviceBridge after sending the DUMP command to the ViewServer to get the control list, will each control information is parsed out, and then create a ViewNode control instance set up a control tree.
  • DeviceBridge dependent Device: HierarchyViewer in calling DeviceBridge setupViewServer to will it hold the device instance to DeviceBridge ViewServer, DeviceBridge is through the example of the device to tissue corresponding ADB commands to send to the ADB server to operate ViewServer
  • Device dependent AdbHelperDevice itself does not connect to the ADB server socket to send commands, which are made by AdbHelper, we have seen in the previous chapter
  • ViewNode combination Window: each ViewNode has a Window member variable. That is to say that each control should belong to a window, and a control that does not belong to a window is meaningless, it should not exist.
  • HierarchyViewer using ViewNodeWhen the script is called findElementById DeviceBridge, the HierarchyViewer is used to get the control list and set up the control tree, and the control tree is traversed by the ViewNode instance.

HierarchyViewer architecture is almost the same as described here, we will go down to the details to see how it is realized.

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:18:28 2015/12/8Original link
Read: 132 comments: 0View comments
]]>
The 1 chapter of the fourteenth section "MonkeyRunner source analysis" HierarchyViewer implementation principle - oriented control programming VS oriented programming Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212877 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212877 Zhubaitian 9:17:42 2015/12/8 So far we have described the MonkeyRunner to the application of the click and drag and so on are directly through the specified coordinates to achieve, such as the following touch of a coordinate point for the (60,90) button script example:

1 device.touch (60900, MonkeyDevice.DOWN_AND_UP)
Code 14-1-1 using the coordinate point operation

  This code will have the following several major drawbacks:

  • Lack of ease of use: to operate a control before you need to think of ways as through the tool to locate the coordinates of the control points
  • Scalability difference: when the screen resolution changes need to write a general algorithm to deal with the change of coordinates
  • Poor readability: Code everywhere is the coordinates of the X, y value, let people see a headache. This is like using the java programmer to look at the assembly code
  • Reusability poor: when changing the screen resolution if does not provide a general algorithm to automatically calculate the new coordinates, we need according to different resolutions for different X and Y coordinates to test

Since there are so many shortcomings in the direct coordinate points, then there is no better way to eliminate these problems? The answer is yes, this chapter describes the HierarchyViewer is specifically to address these issues. When a user needs to operate a control, it is no longer directly through the coordinates of the positioning, but through the control ID first get the control, and then through the control of the coordinates of the positioning. In this process, the user does not need to know the coordinates of the control is how much, because it is encapsulated in the properties of the control, which is from the end of the target Android devices, so even if the test machine, the screen resolution has no effect, the code can continue to run.

If the ID button is "id/button" in the above instance, the script code that gets the control's way through the button will be as follows:

1 viewer = device.getHierarchyViewer ()
2 view = viewer.findViewById ("id/button")
3 P = viewer.getAbsoluteCenterOfView (view)
4 device.touch (p.x, p.y, MonkeyDevice.DOWN_AND_UP)
Code 14-1-2 is applied to the control operation

You can see the change in the control coordinates that the user does not need to care about the screen resolution changes. So it can be said that HierarchyViewer makes MonkeyRunner look closer to the UI automation testing framework for the control.

Of course, HierarchyViewer in addition to providing the function of a control based on ID positioning, but also to provide some other functions, such as the control of the ID to obtain the Text attribute of the control, which we will analyze the.

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:17:42 2015/12/8Original link
Read: 130 comments: 0View comments
]]>
The 7 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - Summary Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212835 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212835 Zhubaitian 9:16:19 2015/12/8 Finally, we make a summary of the process of MonkeyRunner, of course, which also includes starting Monkey, although it does not belong to the part of the boot process:

  • Monkeyrunner this shell script will first set up some of the operating environment system attributes to the System.Propery JVM
  • Then the script will run directly through the -jar monkeyruner.jar SDK Java
  • Then the operating system directly back to the monkeyrunner in the MonkeyRunnerStarter inside the entrance function main
  • The entry function will try to first instance the instance of MonkeyRunnerStarter
  • When MonkeyRunnerStarter is an instance of the, the class is to be ChimpChat.
  • To create a AndroidDebugBridge object to create a ChimpChat object to start a ADB server process to communicate with the ADB server and the target device ADB
  • The DeviceMonitor object is created on the basis of the AndroidDebugBridge object that is created on the ChimpChat object and starts a process to monitor and maintain the Device list of the Android device that is connected to the host PC, because the monitoring device needs to be implemented by sending different control commands to the ADB server. Such as monitoring equipment to the ADB server to send "track-devices host:" service request to the server to get the latest list of the ADB server to send the PID server to monitor each of the debug process needs to send "track-jdwp".
  • After all of the above are ready, try to start the Jython console or directly call the Jython compiler to parse the script
  • In the MonkeyRunner boot process above, the monkey starts with a series of calls that are initiated by the user. The waitForConnection will create two very important device objects, one is the ChimpManager object which is specialized for processing the monkey request; one is the instance of the AdbChimpDevice class that contains the monkey Device ADB

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:16:19 2015/12/8Original link
Read: 130 comments: 0View comments
]]>
The 6 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - start Monkey Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212819 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212819 Zhubaitian 9:15:42 2015/12/8 You may wonder why the monkey process starts with the target device to be put on the "run test script".

Throughout the entire MonkeyRunner boot process, we see that the monkey process is not mentioned in the start of the place. So it's strange, when monkey was started by MonkeyRunner?

Almost without exception, we need to implement a call to MonkeyRunner.waitForConnection (), if there are multiple devices connected to the host's words also need to specify the device serial number, you can also specify the Timeout time waiting for the connection, such as: MonkeyRunner.waitForConnection (XXX, 10000), where XXX represents the serial number, 10 seconds on behalf of 10000 seconds; if not specified parameters, then the framework will provide the default parameters. In fact, the start of the monkey is done in some of the waitForConnection column call.

What is the purpose of the MonkeyRunner call waitForConnection? As the name suggests, of course, is waiting for the connection on the device. But reflect think again wrong, in the above MonkeyRunner start running, not already in the boot device monitor thread DeviceMonitor create a list of representative of the target device device types of mDevices the?? Show that the device is connected to it. At this time, even if we don't run any monkeyrunner script, send the "devices ADB" command to list all the connected devices. So is it the name Google waitForConnection to give up? In fact, is not, where waitForConnection is indeed waiting for the connection of the device, just waiting for the Device device is not connected to the connection, because the device is indeed the device to monitor the thread when the time has been connected to the AdbChimpDevice, and here is to connect the device to connect. Here you may be confused, what is this equipment? Here in fact there are a few Abstract device classes (Abstract equipment in here is not to say that these classes are abstract, but said that these types of equipment is really the device in the host end of a virtual Abstract), if I do the following analysis we should be very good understanding:

  • Device (ddmlib): the representative of the device is controlled by ADB
  • ChimpManager (chimpchat): the representative of the device is controlled by money
  • AdbChimpDevice (chimpchat): it is a higher level of abstraction of the device concept, which contains more than Device devices through the ADB control, but also contains the above monkey to control the device, when the call comes to the AdbChimpDevice will be based on what is required to send a command to the ADB server or sent to monkey to decide which device is used
  • MonkeyDevice (monkeyrunner): a high-level abstraction device that can be directly used by the test script, and it is basically distributed to AdbChimpDevice to execute the API

The relationship between Device and AdbChimpDevice and ChimpManager is more clear: AdbChimpDevice has two key member variables, one is the IDevice type, in fact is an instance of Device's parent class; one is an instance of ChimpManager type. In the next chapter, we'll see a call from MonkeyDevice to MonkeyDevice, such as press, which is eventually distributed to AdbChimpDevice, AdbChimpDevice, and monkey to decide whether to send commands through ChimpManager or Device to ADB.


Figure 8-6-1 the key classes involved in the Monkey process

We first analyze the relationship of each class in the class diagram, and describe how the MonkeyRunner is to start the monkey, and then analyze the implementation code.

  • MonkeyRunner: each test script is believed to be the first to use the waitForConnection method to get a MonkeyDevice object to achieve the operation of the click, but then in the script, this class is not a trace of the. It has a ChimpChat instance variable chimpchat, which we have analyzed in the MonkeyRunnerStarter is set up in the time of the. The waitForConnection method will eventually call the waitForConnection method of the ChimpChat class by chimpchat.
  • MonkeyDevice: can be said to be the most frequent use of the script, the operation of the basic all and the target device is accomplished by calling it. It has a large number of methods of operating target devices, such as press, takeSnapShot, type, etc.. Note that it has an impl instance of the iChimpDevice type, and we will see that it is an instance of the AdbChimpDevice, because the AdbChimpDevice is the IChimpDevice interface. According to the above description AdbChimpDevice is a high-level abstraction of the device, which has a ChimpManager instance can send commands to the monkey, but also has a Device instance can send ADB commands to the ADB server
  • ChimpChat: this class we have analyzed in the above boot process, which is the process of the MonkeyRunnerStarter is being, and it will start the process of starting DeviceMonitor and AndroidDebugBridge. After the completion of the MonkeyRunnerStarter constructor, the setChimpChat MonkeyRunner static method is called to set it to the chimpchat's MonkeyRunner. ChimpChat has a mBackend type of IChimpBackend object, in fact, is a AdbBackend object, because according to the analysis of the previous boot process, when the ChimpChat constructor after the AdbBackend object will be saved to the mBackend of the member of the image, waitForConnection ChimpChat method is to call the waitForConnection method AdbBackend
  • AdbBackend: this class also has been analyzed in the above boot process, which is the process of being an instance of the ChimpChat, and the process of it is AndroidDebugBridge, so it holds an instance of AndroidDebugBridge. AdbBackend can call getDevices's AndroidDebugBridge method to get all of the Device devices connected to the waitForConnection, and then to find the target Device device based on the device's serial number to the AdbChimpDevice.
  • AdbChimpDevice: this is the top device that has been highlighted in the front, with an device instance representing the ADB device, and a manager instance of the monkey device. The waitForConnection method of the MonkeyRunner class is finally obtained by the instance of this class and the MonkeyDevice object is constructed in the process of constructing the impl. The MonkeyDevice press, takeSnapshot, API, MonkeyDevice, type, press, ChimpManager, takeSnapshot, Device, monkey, impl,, type,,,, MonkeyDevice, ADB
  • ChimpManager: represents a monkey device, that is, all monkey related requests are sent to ChimpManager to be processed. It has a number of specialized and monkey communications, such as monkeSocket is used to connect with monkeyWriter, monkey is used to write data to the socket, it is to send a request; monkeyReader is used to read data from the socket, which is to read the request results. At the same time it has a lot of monkey related calls, such as touch, etc.
  • AndroidDebugBridge: this class has been analyzed in the previous MonkeyRunner boot process has been analyzed how it is started up, the main function of the previous description is to start up the ADB server and DeviceMonitor. In this section its main function will be to maintain the DeviceMonitor of this mDeviceMonitor instance, so it can be obtained by Device DeviceMonitor maintenance of the latest list of the. Why get this list, see the description of the AdbBackend class above
  • The main feature of this class in DeviceMonitor: is to provide the getDevices this method to get it to maintain the latest Device device list

With the following basic knowledge, we can analyze the code to explain how the Monkey MonkeyRunner.waitForConnection method in a series of calls initiated by the user to launch a series of calls, we first look at the waitForConnection method MonkeyRunner:

62 static MonkeyDevice waitForConnection public (args PyObject[], KWS String[])
{63
64 AP ArgParser = JythonUtils.createArgParser (args, KWS);
65 Preconditions.checkNotNull (AP);
66 timeoutMs long;
67 try
68 {
69 timeoutInSecs double = JythonUtils.getFloat (AP, 0);
70 timeoutMs = (timeoutInSecs * 1000.0D);
71} catch (E PyException) {
72 timeoutMs = Long.MAX_VALUE;
73}
74
75 IChimpDevice device = chimpchat.waitForConnection (timeoutMs, ap.getString (1, "*"));
76
77 chimpDevice new = MonkeyDevice MonkeyDevice (device);
78 chimpDevice return;
79}
Code MonkeyRunner waitForConnection - 8-6-1

Script calls to the MonkeyRunner, MonkeyDevice, etc. these classes are written by JAVA, and the script itself is written in Jython (which can be called Python JAVA), so they need to have a conversion mechanism, as to how they are not the focus, so I have not studied the principle of Jython, because it does not affect my understanding of MonkeyRunner framework. Well, we continue to analyze the above code:

  • Line 75: call the waitForConnection method of the chimpchat object to obtain an instance of a AdbChimpDevice high level abstract device
  • 79-78 line: the above AdbChimpDevice instance as a parameter to the MonkeyDevice to construct a MonkeDevice object and return to the test code, so that the code can be used to control the target device through the operation of the MonkeyDevice instance

We focus on the analysis of the waitForConnection ChimpChat method, as for the MonkeyDevice constructor, we will have a detailed analysis of the operating principle of the entire MonkeyDevice in the next chapter.

89 IChimpDevice waitForConnection public (timeoutMs long, deviceId String)
{90
91 this.mBackend.waitForConnection return (timeoutMs, deviceId);
92}
98 IChimpDevice waitForConnection public ()
{99
100 return this.mBackend.waitForConnection (2147483647L, "*");
101}
Code ChimpChat waitForConnection - 8-6-2

ChimpChat provides two waitForConnection methods, one of which is non parametric, which is equivalent to the user in a script called MonkeyDevice.waitForConnection directly ();The other is a parameter long type timeout and device serial number. No matter which method ChimpChat is very simple only one line, the call is mBackend waitForConnection. Only if the user does not provide a parameter, ChimpChat will initialize default timeout and equipment serial number of the two parameters, the equipment serial number will be initialized to a regular expressions. "And to represent arbitrary a first find the equipment. The mBackend here is the AdbBackend object that is in the process of analyzing "start AndroidDebugBridge", so we want to locate the waitForConnection method of the class.

116 IChimpDevice waitForConnection public (timeoutMs long, deviceIdRegex String)
117 {
118 do {
119 device IDevice = findAttachedDevice (deviceIdRegex);
120
121 (if (device! = null) and (device.getState) (= = IDevice.DeviceState.ONLINE) {)
122 chimpDevice IChimpDevice =
AdbChimpDevice new (device);
123 this.devices.add (chimpDevice);
124 chimpDevice return;
125}
126 try
127 {
128 Thread.sleep (200L);
129} catch (E InterruptedException) {
130 LOG.log (Level.SEVERE, "sleeping Error", e);
131}
132 timeoutMs = 200L;
133} while (timeoutMs > 0L);
134
135
136 null return;
137}
Code AdbBackend waitForConnection - 8-6-3

The method will do a while loop waiting to find a device that is in agreement with the user supplied or the default serial number. If the device is found, the device is used as a parameter to construct a AdbChimpDevice instance object and return it:

  • Line 133: enter the while cycle, if the time is not connected to the target device has been circulating in the timeout
  • 128 and 132 lines: each cycle if there is no connection with the target device then sleep 0.2 seconds and then the next cycle
  • 119 line: according to the equipment provided by the serial number (regular expression) to find the target Device equipment, where to find it? In fact, go to the DeviceMonitor to monitor the thread object maintenance in the latest Device device queue to find
  • 122 line: after finding the target Device device, the device object is passed into the constructor of the AdbChimpDevice to the object and returns the AndroidChimpDevice object. We can see that the AdbChimpDevice will go to the ChimpManager object to start the monkey to start the communication.

We first analyze the 119 line findAttachedDevice is how to find the target Device according to the device serial number, and then to analyze how the AdbChimpDevice is constructed. We first go to the findAttachedDevice method:

99 IDevice findAttachedDevice private (deviceIdRegex String)
100 {
101 pattern Pattern = Pattern.compile (deviceIdRegex);
102 for (device IDevice: this.bridge.getDevices ()) {
103 serialNumber String = device.getSerialNumber ();
104 if (pattern.matcher (serialNumber).Matches ()) {
105 device return;
106}
107}
108 null return;
109}
Code AdbBackend findAttachedDevice - 8-6-4

In the third section, we have learned that AdbBackend is saved to its own bridge member object after the AndroidDebugBridge object is initialized, so this method is done by using this AndroidDebugBridge instance to get all the latest Device device list (102 lines), and then compare the sequence number of each Device device with the parameters provided by the 103-105.

Let's see how we get the list of devices:

482 IDevice[] getDevices public ()
483 {
484 synchronized (sLock) {
485 if (this.mDeviceMonitor = null) {
486 this.mDeviceMonitor.getDevices return ();
487}
488}
489
490 new IDevice[0] return;
491}
Code AdbBackend getDevices - 8-6-5

After the AndroidDebugBridge object, the object is saved to the mDeviceMonitor member variable, which is saved by the DeviceMonitor object. Here getDevices's AndroidDebugBridge method is to call its getDevices method to get the latest list of devices in the DeviceMonitor object:

129 getDevices Device[] ()
130 {
131 synchronized (this.mDevices) {
132 return (Device[]) this.mDevices.toArray (New
Device[this.mDevices.size ()]);
133}
134}
Code DeviceMonitor getDevices - 8-6-6

In the fourth section of the boot device monitor thread DeviceMonitor, we have learned that when the DeviceMonitor is sent to the ADB server to monitor the command "host:track-devices", once the device is monitored to increase or remove or change the status of the device, the device will be updated to the Device of the mDevices list. The whole list is returned by the method.

Code AdbBackend findAttachedDevice - findAttachedDevice, 8-6-4 in the list of this device, will remove the serial number of each device and the target device serial number to find a match to find the match directly to the device to return, then we look at its corresponding method of obtaining the serial number device.getSerialNumber ():

244 String getSerialNumber public ()
245 {
246 this.mSerialNumber return;
247}
Code Device getSerialNumber - 8-6-7

Directly returned is the Device device to save the mSerialNumber variable, the variable is represented by the corresponding equipment of the serial number. We should also remember the fourth section of the boot device monitor thread DeviceMonitor to analyze to the processIncomingDeviceData method, once the ADB server will be sent to the latest device list and device status to initialize the Device device to the device's serial number, the device state to the Device device corresponding to the mSerialNumber and mStat member variables.

After obtaining alignment equipment serial number, findAttachedDevice will be to provide the serial number for comparison, if there is a match, it returns to the caller code 8-6-3 AdbBackend - waitForConnection, "the. And the waitForConnection AdbBackend in the case of access to the AdbChimpDevice will pass it to the constructor of the Device to construct an instance of the AdbChimpDevice object. We look at how its constructor is done:

68 AdbChimpDevice public (device IDevice)
{69
70 this.device = device;
71 this.manager = createManager ("127.0.0.1", 12345);
72
73 Preconditions.checkNotNull (this.manager);
74}
Code AdbChimpDevice 8-6-8 constructor

As has been emphasized, the AdbChimpDevice is a very important class, it is a high-level abstraction of the device object, which combines the ChimpManager and ADB through the monkey control device Device. This combination relationship is embodied by the above AdnbChimpDevice constructor. The combination of the seventieth line is the Device device, the combination of the 71 is the ChimpManager instance. Just Device instance is the start of the device to monitor the thread DeviceMonitor has been created to create good, and ChimpManager is created at this time. Create time specified is the loopback IP address "127.0.0.1", monkey is designated port local forwarding port 12345

The code to create a ChimpManager createManager code is a bit long, we will be divided into two parts to analyze, the first part is to start Monkey, the second part is to create ChimpManager. Let's look at the first part first:

123 ChimpManager createManager private (address int, port String) {
124 try {
125 this.device.createForward (port, port);
126} catch (E TimeoutException) {
127 LOG.log (Level.SEVERE, "creating ADB port forwarding Timeout", e);
128 null return;
129} catch (E AdbCommandRejectedException) {
130 LOG.log (Level.SEVERE, "rejected ADB port forwarding command: Adb" + e.getMessage (), e);
131 null return;
132} catch (E IOException) {
133 LOG.log (Level.SEVERE, "to create ADB port forwarding: Unable" + e.getMessage (), e);
134 null return;
135}
136
137 command String = "--port monkey" + port;
138 executeAsyncCommand (command, LoggingOutputReceiver new (LOG, Level.FINE));
139
140 try
141 {
142线程睡眠(1000L);
143 } catch(InterruptedException e){
144日志。日志(level.severe,“无法入睡”,E);
145 }
146 InetAddress addr;
147试
148 {
149 = InetAddress addr通过getByName(地址);
150 } catch(unknownhostexception e){
151日志。日志(level.severe,“无法转换地址到它:“+地址,E);
152返回空;
153 }
…
}
代码8-6-9 adbchimpdevice - createmanager之启动猴

createmanager首先做的事情就是去把目标设备端的猴子服务进程给启动起来接收monkeyrunner测试脚本发送过去的请求。代码流程如下所示:

  • 125行:设置本机到目标机器猴子进程监听端口的端口转发,调用的是装置的createforward的方法,这个方法我们在下一章描述装置类详解的时候会进行分析。这里只需要它基本可以看作是在命令行发送“亚行提出12345 12345“来完成从本机12345端口到远程猴子监控的12345端口的转发就好了。设置好端口转发后往下的代码就能直接连接本机的12345端口,这就等同于连上的是远端目标设备中猴子监听的12345端口了
  • 139-138行:设置好猴子端口转发后,createmanager方法就会往亚行服务器发送壳命令“猴子——端口12345”来启动猴子去监听端口12345。发送adb shell命令使用的方法是createasynccommand方法,其实该方法没有什么好分析的,因为它把发送命令请求直接转发给装置类的executeshellcommand而已,而executeshellcommand这个方法我们也是在下一章会进行分析
  • 149行:将本机监听地址“127.0.0.1”转换成InetAddress对象格式,这样往下创建插座连接的时候才能直接使用

createmanager之启动猴子到了这里就完成了,往下我们继续看第二部分createmanager之创建chimpmanager:

123私人chimpmanager createmanager(字符串的地址,端口){
…/ /启动猴子代码略
159布尔成功=假;
160 chimpmanager毫米= null;
161长currenttimemillis()开始=系统;
162
163而(!成功){
164现在currenttimemillis() =系统;
165长差异=现在开始;
166如果(diff > 30000 L){
167日志。严重(“超时而试图创建黑猩猩经理”);
168返回空;
169 }
170试
171 {
172线程睡眠(1000L);
173 } catch(InterruptedException e){
174日志。日志(level.severe,“无法入睡”,E);
175 }
176插座monkeysocket;
177试
178 {
179 monkeysocket =新的套接字(地址、端口);
180 } catch(IOException e){
181日志。日志(level.fine,“无法连接插座”,E);
182成功=假;
183继续;
184
185试
186 {
187毫米=新chimpmanager(monkeysocket);
188 } catch(IOException e){
189日志。日志(level.severe,“无法打开作家和读者对插座”);}
190继续;
191
192试
193 {
194毫米。wake();
195 } catch(IOException e){
196日志。日志(level.fine,“无法叫醒装置”,E);
197成功=假;
198继续;
199
200成功=真实;
201 }
202
203返回毫米;
}
代码8-6-10 adbchimpdevice - createmanager之创建chimpmanager

3个事情其实上面一堆代码无非是在一个循环中做了:

  • 179行:创建连接到本机猴子转发端口的插座对象
  • 187行:根据该插座对象构造chimpmanager实例,chimpmanager的详细分析会放到下一章的描述chimpmanager类详解的时候进行分析
  • 194行:往猴子发送命令去唤醒休眠屏幕,如果屏幕是在休眠状态的话的原理也会在下一章进行分析唤醒。

分析到这里这一小节的目标就已经达到了,我们已经学习到了猴子服务进程是如何在脚本中通过调用monkeyrunner的waitforconnection方法启动起来的了,同时我们也学习到了adbchimpdevice和chimpmanager这两个关键类创建的相关知识点。

In the next section, we try to summarize what we have learned in this chapter.

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:15:42 2015/12/8Original link
Read: 124 comments: 0View comments
]]>
The 5 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - run test script Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212811 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212811 Zhubaitian 9:15:14 2015/12/8 After the AndroidDebugBridge and DeviceMonitor, MonkeyRunner and other services, it is basically resolved the problem of communication with the target device, and that is to do is to run the test script.

178 static void main public (args String[]) {
179 options MonkeyRunnerOptions = MonkeyRunnerOptions.processOptions (args);
180
181 If (options = = null) {
182 return;
183}
184
185
186 replaceAllLogFormatters (MonkeyFormatter.DEFAULT_INSTANCE, options.getLogLevel ());
187
188 runner new = MonkeyRunnerStarter MonkeyRunnerStarter (options);
189 error int = runner.run ();
190
191
192 System.exit (error);
193}
194}
Code MonkeyRunnerStarter Main - 8-5-1

From the above code and the above sections of this chapter, MonkeyRunnerStarter starts the AndroidDebugBridge and DeviceMonitor in the process of MonkeyRunnerStarter, and then goes to the next line to call run's MonkeyRunnerStarter method.

66 int run private ()
{67
68 monkeyRunnerPath String =
System.getProperty ("com.android.monkeyrunner.bindir")
+
File.separator + "monkeyrunner";
69
70
71 Map<String, plugins Predicate<PythonInterpreter>> = handlePlugins ();
72 (if) (this.options.getScriptFile = = null) {
73 ScriptRunner.console (monkeyRunnerPath);
74 this.chimp.shutdown ();
75 return 0;
76}
77 error int = ScriptRunner.run (monkeyRunnerPath,
This.options.getScriptFile () this.options.getArguments (),.GetAbsolutePath (), plugins);
78
79 this.chimp.shutdown ();
80 error return;
81}
Code MonkeyRunnerStarter run - 8-5-2

  • Line 68: get the absolute path to the monkeyrunner script. "Com.android.monkeyrunner.bindir" we have analyzed in front, it represents the "/tools" in your SDK installation directory, and then add the file separator / "and" monkeyrunner ". So the end result is similar to "/Users/apple/Develop/sdk/tools/monkeyrunner""
  • 72-73 line: if the user does not provide the script file path to the command line running monkeyrunner, then call the ScriptRunner class console to request the Jython parser to open an interactive window to allow users to interact.
  • Line 74: when the user closes the window, call the shutDown ChimpChat method to notify the corresponding module test has been stopped, so that they do the appropriate processing. For example, the monkey service will be sent to the "quit" command, which will be stopped.
  • Line 77 line: if the user provides the script path to the monkeyrunner when the command line runs Jython, the run method of the ScriptRunner will be run, which will eventually call the parser to run the script.

Whether it is open interactive console or directly run the script, the end use is the Jython parser to do things, such as we go into the run ScriptRunner method:

77 static int run public (executablePath String,
Scriptfilename String,
Args Collection<String>,
Predicate<PythonInterpreter>>, plugins Map<String)
{78
...
94 Python new = PythonInterpreter PythonInterpreter ();
...
114 try
115 {
116 python.execfile (scriptfilename);
117}
...
}
Code ScriptRunner run - 8-3-3

The thing to do is to go to an Jython parser, where the PythonInterpreter is "org.python.util" ". After you get the Jython parser, you call the parser's execfile method directly to the target test script.

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:15:14 2015/12/8Original link
Read: 130 comments: 0View comments
]]>
The 4 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - start AndroidDebugBridge Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212779 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212779 Zhubaitian 9:14:34 2015/12/8 The last section we see in the process of starting the AndroidDebugBridge will call its start method, and the method will do 2 main things:

  1. 715 line startAdb: open AndroidDebugBridge
  2. 722-723 line: initialize the Android device to monitor and start the DeviceMonitor device monitor thread.

The first point we have done a detailed analysis of the last section, then we go down to analyze the first 2 points.

The main function of the DeviceMonitor is to monitor if there is an Android device to pull out or connect, and then monitor all the adjustable processes on each of the connected devices. This feature is more for the DDMS this debug tool used by everyone from the AndroidDebugBridge jar ddmlib.jar package should be able to guess what is actually used jar DDMS.

Every Android applications are run in separate processes, and each process is running in its own virtual machine (VM). In fact, this is basically the concept of Android operating system sandbox and sandbox is developed). The purpose is to prevent you from the process of breaking the process everywhere. Each process of the VM will provide a unique port for connecting the debugger. DDMS is connected to AndroidDebugBridge (which is the ADB server). When a device is connected to the device, a virtual machine will notify the DDMS when the device is started or stopped, creating a virtual machine monitoring service between ADB and DDMS. Once the virtual machine is running, DDMS will retrieve the ID (PID) of the virtual machine through the DeviceMonitor AndroidDebugBridge thread, and open a connection to the virtual machine by the ADB guard process on the device. So DDMS will be able to talk to the virtual machine.


Figure DDMS 8-4-1 interface

DeviceMonitor this class for the MonkeyRunner framework for the most important feature is that it holds a list of all connected devices, the Device class is very important, the basic can be said that the MonkeyRunner and ADB server communication is finally through it, so it is equivalent to an Android device in the PC side of the proxy, we next chapter will be a detailed analysis of this class. Below we look at this class DeviceMonitor:


Figure DeviceMonitor 8-4-2 class

This class is a class of ddmlib libraries, which lists the key member variables and methods for DeviceMonitor, and we first make a preliminary introduction to them, so that we can better follow my source code for this class:

  • DebugBridgeServer mServer: object, because you need to send the ADB server to the corresponding device monitoring command, so in the DeviceMonitor initialization of a DebugBridgeServer instance will be sent to save the mServer
  • MMainAdbConnection: a SocketChannel instance, DeviceMonitor in the monitoring of each device before the need to establish a link with the ADB server
  • MDevices: represents a list of the Device instances of an Android device.Note that this Device is very important in the entire MonkeyRunner framework, as described above, it can be seen as a proxy for real Android devices in the PC terminal, and many of the commands sent to the ADB server are eventually sent out by it. DeviceMonitor monitor thread once found the new device will create a Device instance and put it into the mDevices list, on the contrary, if a device is removed, it will be removed from the mDevices list
  • Start: a default permission method, so it can be the same ddmlib package inside the AndroidDebugBridge call. Its role is to start the device list monitoring thread, the thread of the main body in the following description of the deviceMonitorLoop method
  • GetDevices: returns the above mDevices device. The waitForConnection method of the MonkeyRunner class will eventually call this method to obtain all the equipment and find the target device to connect to the device.
  • DeviceMonitorLoop: to ADB server to send "host:track-devices" equipment monitoring command to cycle to obtain the latest string type equipment list, this command is similar to in the command line send "ADB devices" to acquire the equipment list of the current connection, but different places is the monitor commands are sent to the server by the ADB, the ADB server will periodically update the equipment list and take the initiative to send back. After each cycle is completed, if the ADB server has data, it will call the following processIncomingDeviceData method to update the list of mDevices devices and other issues.
  • DeviceMonitorLoop above the sendDeviceListMonitoringRequest: method call from the ADB server to send the host:track-devices device list monitoring command method
  • ProcessIncomingDeviceData: above deviceMonitorLoop in discovering the ADB server data over time will call this method to from the socketchannel mMainAdbConnection connected with the ADB server to read out the latest string type equipment list and for each device to instantiate a device instance and the instance into a list and send to the following updateDevices method to handle
  • UpdateDevices: after receiving the latest Device type of processIncomingDeviceData, updateDevices will check on the mDevices device list to check which devices are new additions, which are removed, and which are the state changed to handle:
    • New device: add the device to the DeviceMonitor mDevices device list, and call the following startMonitoringDevice to create a monitoring thread for each of the device's debug applications to monitor the VM process.
    • The device becomes a ONLINE state: the mDevices device is set to the ONLINE state, and the startMonitoringDevice is called to create a monitoring thread to monitor the VM process.
    • Equipment from the ONLINE into other states: the mDevices device list inside the corresponding device is set to the corresponding state
    • Remove device: remove the device from the current device list mDevices
  • StartMonitoringDevice: to obtain the corresponding device in the VM process of all the PID list (can debug process refers to the DalvikVM of each JDWP thread to make DDMS and other debugging tools connection process), connect each VM debug port and establish the corresponding client monitoring thread to monitor the process. Because the client machine lower level of the JDWP code is mainly to the DDMS and other monitoring and control debugging tools, so this book will not be a thorough analysis
  • StartMonitoringDevice sendDeviceMonitoringRequest: method calls this method to obtain the PID of all the processes that the specified device can debug, in fact, the track-jdwp command is sent.

With the basic understanding of the above, we continue to analyze the code to achieve. After the AndroidDebugBridge start up, the next step is to put the ADB instance to the DeviceMonitor to monitor all the connected to the ADB server is the PC host Android device state:

70 DeviceMonitor (server AndroidDebugBridge)
{71
72 this.mServer = server;
73
74 this.mDebuggerPorts.add (Integer.valueOf (DdmPreferences.getDebugPortBase));
75}
Code DeviceMonitor 8-4-1 constructor

After a good example of AndroidDebugBridge, the next step is to continue the AndroidDebugBridge start function start () to start the DeviceMonitor device monitoring thread:

79 start void ()
{80
81 Thread new ("List Monitor Device")
82 {
83 void run public () {
84 DeviceMonitor.this.deviceMonitorLoop ();
85}
86}.start ();
87}
Code DeviceMonitor start - 8-4-2

Line 81-86, the main body of the method is to create a "List Monitor Device" thread. Thread running method run directly call the deviceMonitorLoop DeviceMonitor method to infinite loop monitoring device state.

155 void deviceMonitorLoop private ()
156 {
157 do
158 {
159 try
160 {
161 if (this.mMainAdbConnection = = null) {
162 Log.d ("DeviceMonitor", "ADB connection Opening");
163 this.mMainAdbConnection =
OpenAdbConnection ();
164 If (this.mMainAdbConnection = = null) {
165 this.mConnectionAttempt = 1;
166日志。E(“设备显示器”、“连接尝试:“+,mconnectionattempt);
167如果(this.mconnectionattempt > 10){
168如果(!这个操作。startadb()){
169 this.mrestartattemptcount + = 1;
170日志。E(“设备显示器”、“亚行重新尝试:“+,mrestartattemptcount);
171 }
172 {
173 this.mrestartattemptcount = 0;
174 }
175 }
176 waitabit();
177 } {
178日志。D(“设备显示器”、“与亚行装置监控”);
179 this.mconnectionattempt = 0;
180 }
181 }
182
183如果((this.mmainadbconnection!=空)&
(!这个监测)){
184 this.mmonitoring = senddevicelistmonitoringrequest();
185 }
186
187如果(这。监测)
188 {
189 int length = readlength(this.mmainadbconnection,这个mlengthbuffer);
190
191如果(长度= 0)
192 {
193 processincomingdevicedata(长度);
194
195
196 this.minitialdevicelistdone =真;
197 }
198 }
199 }
200抓(asynchronouscloseexception ACE){ } catch(TimeoutException IOE)
201 {
202 handleexpectioninmonitorloop(IOE);
203 } catch(IOException IOE){
204 handleexpectioninmonitorloop(IOE);
205 }
206 }!这mquit);
207 }
代码8-4-3设备显示器- devicemonitorloop

  • 第一步:163行,如果还没有连接上的亚行服务器的话就先连接上
  • 第二步:168行,确保亚行服务器已经启动
  • 第三步: 行183-185,往亚行服务器发送监控命令,监控所有连接上来的移除的设备
  • 第四步:处理所获得的监控设备列表

我们先看第一步,在上一节中我们已经看到亚行服务器的启动过程了,但是我们还没有看到亚行客户端是怎么连接上服务器的,一下的代码就是一个实例:

255私人SocketChannel openadbconnection()
256 {
257日志。D(“设备显示器”、“连接到设备列表亚行监测…”);
258
259 adbchannel SocketChannel = null;
260尝试{
261 adbchannel =
开放(SocketChannel。
androiddebugbridge getsocketaddress());
262 adbchannel。socket() settcpnodelay(真的);
263 }
264抓(IOException e){ }
265
266回adbchannel;
267 }
代码8-4-4设备显示器- openadbconnection

261行创建一个和亚行服务器监听的插座端口的一个异步非阻塞SocketChannel连接,该连接就是专门用于往后往亚行服务器发送命令用的,返回给devicemonitorloop方法后会被保存到mmainadbconnection中,请大家记住它,我们往下会用到它。

第二步关于如何调用startadb来开启亚行服务器是上一节的重点,所以我们不会重新分析了。

第三步是向亚行服务器发送设备监控命令,我们跳进去:

272私人布尔senddevicelistmonitoringrequest()
273抛出IOException TimeoutException,
274 {
275字节[ ]请求=
adbhelper。formadbrequest(”主持人:跟踪设备”);
276试
277 {
278 adbhelper写(this.mmainadbconnection,请求);
279
280 adbhelper.adbresponse RESP = adbhelper readadbresponse(this.mmainadbconnection,假);
281
282
283如果(!为好)。
284 {
285日志。E(“设备显示器”、“亚行拒绝请求:“+或消息);
286 }
287
288回resp.okay;
289 } catch(IOException e){
290日志。E(“设备显示器”、“发送跟踪请求失败!”);
291本。mmainadbconnection。();
292扔;
293 }
294 }
代码8-4-5设备显示器- senddevicelistmonitoringrequest

整个方法的功能就是去构建一个发送到亚行服务器请求服务的命令,然后发送,读取结果,返回,错误处理:

  • 275: send constructs a request to the server by the ADB get equipment control command string "host:track-devices", we in the next chapter described the monkeydevice principle will describe in detail formAdbRequest is how to construct a ADB service request command
  • 278 line: the mMainAdbConnection AdbHelper method to the above established write SocketChannel connection with the ADB server to write the request, and the write method is the final call of the write SocketChannel method to write data to Socket, we describe the MonkeyDevice in the next chapter will be described in detail
  • Line 280: with the write Socket corresponding to read Socket, after the command will call the readAdbResponse AdbHelper method to send the results read out the command to return, pay attention to the success or failure of the command sent here, not to return the list of devices. In the next chapter, we describe the method of readAdbResponse in detail.

Corresponding to the implementation details of the corresponding AdbHelper method we will describe in detail the next chapter. Here we only need to know how to do this thing is just referred to the ADB server to send "host:track-devices" command to request the corresponding equipment monitoring service is enough. So what is the service request? In fact, this has been described in the first chapter, used to make the ADB server periodically to the client, that is, the DeviceMonitor thread to send equipment updates here:

Host:track-devices

This service is a variant of the host:devices, the client and the ADB server connection will be maintained, when there is an increase / removal of the device or device status changes will take the initiative to connect to the client to send a new device list information (4 byte 16 hex length + content). In this way, DDMS can be used to track the status of all connected devices in real time, without the need for a client to connect to the ADB server to obtain the corresponding information.

This command returns the form devices ADB, which is called the ADB command line client, to return to the format of the device's serial number: Figure ADB devices 8-4-2 command returns the result

Note that the state of the device is in fact oneline, which is defined in the IDevice class of ddmlib:

86 static enum DeviceState public {BOOTLOADER ("bootloader"),
87 OFFLINE ("offline"),
88 ONLINE ("device"),
89 RECOVERY ("recovery"),
90 UNAUTHORIZED ("unauthorized");
91
92 String mState private;
93
94 DeviceState private (state String) {
95 this.mState = state;
96}
Code IDevice DeviceState - 8-4-6

The "host:track-devices" command sends a periodic server to the list of devices that are sent to the ADB server once a time, so the previous deviceMonitorLoop loop can be simplified to the following code:

155 void deviceMonitorLoop private ()
156 {
157 do
158 {
159 try
160 {
...
187 if (this.mMonitoring)
188 {
189 length int = readLength (this.mMainAdbConnection,
This.mLengthBuffer);
190
191 if (length = 0)
192 {
193 processIncomingDeviceData (length);
194
195
196 this.mInitialDeviceListDone = true;
197}
198}
199}
...
206} while (this.mQuit);
207}
DeviceMonitor deviceMonitorLoop - 8-4-3 simplified version

So the end point is to call processIncomingDeviceData to handle the updated list of devices.

296 void processIncomingDeviceData private (length int) IOException throws
297 {
298 list new = ArrayList ArrayList<Device> ();
299
300 if (length > 0) {
301 buffer new = byte[length] byte[];
302 result String = read (this.mMainAdbConnection, buffer);
303
304 devices String[] = result.split ("\n");
305
306 for (D String: devices) {
307 param String[] = d.split ("\t");
308 if (param.length = 2)
309 {
310 device new = Device Device (this, param[0],
IDevice.DeviceState.getState (param[1]));
311
312
313
314 list.add (device);
315}
316}
317}
318
319
320 updateDevices (list);
321}


Code DeviceMonitor processIncomingDeviceData - 8-4-4

The method first obtains a list of devices in the 302 row of ADB server, and then sends the sequence number of each device to a Device object and stores it into a list list. Finally, the next step is to call the updateDevices method. This is a simple look at the Device constructor, as for its detailed analysis will be left to the next chapter.

677 Device (monitor String, serialNumber DeviceMonitor, deviceState IDevice.DeviceState)
678 {
679 this.mMonitor = monitor;
680 this.mSerialNumber = serialNumber;
681 this.mState = deviceState;
682}
Code Device 8-4-5 constructor

The constructor of the device is very simple, is the coming from the above DeviceMonitor examples, the ADB server active sent the equipment serial number strings, and the current state of the equipment to save up to the corresponding member variable. Here to pay attention to the taxi mSerialNumber and mState, in the next analysis to start Monkey, we need to use.

We continue to analyze the updateDevices method. This method has a little bit longer code, we put it in a separate analysis:

323 / * *
324 * the device list with the new items received from the monitoring service. Updates
325.
326 void updateDevices private (newList ArrayList<Device>) {
327 we are going to / / because call mServer.deviceDisconnected which will acquire this lock
328 / / we lock it first, so that the AndroidDebugBridge lock is always locked first.
329 synchronized (AndroidDebugBridge.getLock ()) {
330 to store the devices / / array that must be queried for information.
331 important to not do / / it's it inside the synchronized loop as this could block
332 / / the whole workspace (this lock is acquired during build too).
333 devicesToQuery new = ArrayList<Device> ArrayList<Device> ();
334 synchronized (mDevices) {
335 For device in the current / each list, we look for a matching the new list.
336 / / we find * if it, we update the current object with whatever new information
337 / / there is
338 / (mostly state change if the device becomes ready, we query for build info).
339 also remove the device / / We from the new list to mark it as processed ""
340 / / we do not find * if it, we remove it from the current list.
341 / / Once this is done, the new list contains device we aren't monitoring yet, so we
342 / / add them to the list, and start monitoring them.
343
344 for (d int = 0; d < mDevices.size ();) {
345 device Device = mDevices.get (D);
346
347 look for a similar device in / the new list.
348 count int = newList.size ();
349 foundMatch Boolean = false;
350 for (DD int = 0; DD < count; dd++) {
351 newDevice Device = newList.get (DD);
352 see if it matches in ID / and serial number.
353 if (newDevice.getSerialNumber ().Equals (device.getSerialNumber)) {
354 foundMatch = true;
355
356 / / update the state if needed.
357 if (device.getState () = newDevice.getState ()) {
358 device.setState (newDevice.getState ());
359 device.update (Device.CHANGE_STATE);
360
361 if the device just got / ready/online we need to start
362 / / monitoring it.
363 if (device.isOnline ()) {
364 if (AndroidDebugBridge.getClientSupport ()) {
365如果(!startmonitoringdevice(装置)){
366日志E(“设备显示器”,
367“未能开始监控”
368 +设备getserialnumber());
369 }
370 }
371
372如果(装置。getpropertycount() = = 0){
373 devicestoquery添加(设备);
374 }
375 }
376 }
377
378从列表中删除新设备,因为它已被使用
379新删除(DD);
380休息;
381 }
382 }
383
384如果(!foundmatch){
385 / /设备不见了,我们需要清除它,并保持当前索引
386、处理下一个。
387 removedevice(装置);
388操作devicedisconnected(装置);
389 } {
390 / /处理下一个
391天+ +;
392 }
393 }
…
}
代码8-4-5设备显示器- updatedevices处理移除和状态改变设备

这一部分的代码逻辑关系是这样的:

  • 344行:一个外部循环每次从上次保存下来的设备列表获得一个设备装置实例
  • 350行:再在一个内部循环从最新的设备列表中获得一个设备装置实例
  • 353行:然后分别比较两个设备的序列号是否相等,相等则代表这个设备没有被移除。
  • 357行:如果设备没有被移除的话,那么判断这个设备是否是状态变化了?
  • 358-373行:变化了就需要把设备的状态改变过来
    • 363-368行:特别是在设备变成离线变成在线状态后,需要去对该设备里面的可调试进程进行监控
    • 两行:并把该设备标识成还没有获取基本信息的状态,因为每个已经连接的在线设备都应该保存有基本的建立等信息
  • 379行:如果分析完一个设备发现只是状态变化了的话,最后把它从新设备列表中删除掉,因为已经分析过了,下面不需要再使用它了
  • 384-388行:如果设备已经被移除了的话(在新设备列表里面通过序列号找不到了),那么需要把该设备移除出监控范围

以上代码是设备被移除和设备状态有更新时候的处理,那么新设备该怎么处理呢?毕竟一开始设备都是新的,这个才是关键点。

326 updatedevices private void(ArrayList <设备>新){
…
395 / /在这一点上我们还是应该有一些新的新设备,所以我们
396 /处理。
397(设备新:新){
398、将它们添加到列表中
399 mdevices添加(新);
400操作deviceconnected(新);
401
402、启动监控。
403如果(androiddebugbridge。getclientsupport()){
404如果(新装置。isonline()){
405 startmonitoringdevice(新);
406 }
407 }
408
409 /寻找他们的信息。
410如果(新装置。isonline()){
411 devicestoquery添加(新);
412 }
413 }
414 }
415
416、查询新的信息设备。
417(装置D:devicestoquery){
418 querynewdeviceforinfo(D);
419 }
420 }
421 clear()新;
422 }
代码8-4-6设备显示器- updatedevices处理新增加设备

  • 397行:对所有剩余没有处理的新设备做一个循环
  • 399 line: the device to keep the device Device object, the next time you need to update the device with the new device to do a comparison, as the code 5-4-5 to do
  • 404-405: start for new equipment to monitor, in fact plainly is new equipment on the inside of each can be adjustable process VM to establish a client monitoring
  • 418 line: get the basic information of the new equipment, this we finally to analyze

Here we focus on the first 405 lines startMonitoringDevice:

509 Boolean startMonitoringDevice private (device Device) {
510 socketChannel SocketChannel = openAdbConnection ();
511
512 if (socketChannel = null) {
513 try {
514 result Boolean = sendDeviceMonitoringRequest (
SocketChannel, device);
515 if (result) {
516
517 if (mSelector = = null) {
518 startDeviceMonitorThread ();
519}
520
521 device.setClientMonitoringSocket (socketChannel);
522
523 synchronized (mDevices) {
524 always wakeup before doing the register. / The synchronized block
525 ensure the selector won't select / that (before) the end of this block.
526 / / @see deviceClientMonitorLoop
527 mSelector.wakeup ();
528
529 socketChannel.configureBlocking (false);
530 socketChannel.register (mSelector, SelectionKey.OP_READ, device);
531}
532
533 true return;
534}
535}
Omit / / error handling code...
}
Code DeviceMonitor startMonitoringDevice - 8-4-7

514 line first to the ADB server to send a listening request to get all the application process of the PID can debug a list of:

674 Boolean sendDeviceMonitoringRequest private (socket SocketChannel, device Device)
675 TimeoutException AdbCommandRejectedException, throws, IOException {
676
677 try {
678 AdbHelper.setDevice (socket, device);
679
680 request byte[] = AdbHelper.formAdbRequest ("track-jdwp"); //$NON-NLS-1$
681
682 AdbHelper.write (socket, request);
683
684 AdbResponse resp = AdbHelper.readAdbResponse (socket, false / * * / readDiagString);
685
686 if (resp.okay) {
687 / / request was refused by adb!
688 Log.e ("DeviceMonitor", "refused request: ADB" + resp.message);
689}
690
691 resp.okay return;
692}
Omit / / error handling code...
}
Code DeviceMonitor sendDeviceMonitoringRequest - 8-4-8

In fact, this code and the above code DeviceMonitor sendDeviceListMonitoringRequest - 8-4-5 is similar, just send the connection in the 678 line to the target monitoring device (AdbHelper.setDevice method will be in the next chapter, as described in the next chapter) as well as the final command to send the track-jdwp command only. This command is in fact equivalent to you in order to call the ADB command line client to send the command jdwp ADB, to return to the PID of all adjustable application process, please see the following output sample, which is consistent with the process DDMS PID Devices module print 8-4-1:


Figure ADB jdwp 8-4-2 command output

Get to the device running the PID can debug process list, we should also think of the next step is for each PID, which is for each process of VM virtual machine to create a client thread to monitor the debugging through JDWP protocol, which is why DDMS can dynamically obtain the dynamic information of each process.

Process VM (virtual machine monitor code analysis to here in this book should be about even if, if further down analysis is needed to analysis of DDMS more knowledge and jdwp protocol related things, after all, this is not our book will focus on. So the analysis here let big is a basic cognitive principle of DDMS. Further down the analysis of a lot of irrelevant code is sidetracked and Minato words of the suspect.

Here we are on the basis of the above, or to see the code DeviceMonitor updateDevices - 8-4-6 processing of new devices, the 481 line of the new device is how to get basic information by calling the queryNewDeviceForInfo method, what information is acquired:

442 void queryNewDeviceForInfo private (device Device) {
443 TODO: do this in a separate / / thread.
444 try {
445 get the list of properties. / / first
446 device.executeShellCommand (
"Getprop",
447 GetPropReceiver new (device));
448
449 queryNewDeviceForMountingPoint (device,
"EXTERNAL_STORAGE";
450 queryNewDeviceForMountingPoint (device,
"ANDROID_DATA";
451 queryNewDeviceForMountingPoint (device,
"ANDROID_ROOT";
452
453 get the emulator Virtual / / now Device name (if applicable).
454 if (device.isEmulator ()) {
455 console EmulatorConsole = EmulatorConsole.getConsole (device);
456 if (console = null) {
457 device.setAvdName (console.getAvdName ());
458 console.close ();
459}
460}
461}
Omit / / error handling code...
}
Code DeviceMonitor queryNewDeviceForInfo - 8-4-9

What is done by this method:

  • 446 line: Device executeShellCommand AdbHelper method to send a similar shell getprop ADB command to get all the system properties, this method is the final call is the executeShellCommand method, it will receive a special shell getprop command to handle the return value of the receiving class instance. AdbHelper working principle and processing "shell getprop ADB" to return the results of the receiving class GetPropReceiver we are in the next chapter, the seventh chapter MonkeyDevice implementation principle will be described in detail.
  • 449-451: get the file system of several important mountpoints, I believe this is to DDMS File with Explorer function

To obtain the complete system properties, we will see the file system of the new equipment of the mount point is how to get, we have entered into the corresponding method:

483 void queryNewDeviceForMountingPoint final (Device device final, String name private)
484 TimeoutException AdbCommandRejectedException, ShellCommandUnresponsiveException, IOException, throws
485 {
486 device.executeShellCommand ("echo $" + name,
MultiLineReceiver new ()
487 {
488 Boolean isCancelled public () {
489 false return;
490}
491
492 void processNewLines public (lines String[])
493 {
494 for (line String: lines) {
495 if (line.isEmpty ())
496 {
497 device.setMountingPoint (name, line);
498}
499}
500}
501});
502}


Code DeviceMonitor queryNewDeviceForMountingPoint - 8-4-10

This is similar to the getprop command above, but the order is changed to "shell $name ADB" and the return value is the same as that of the processing class. Here $name change into the above call method parameters corresponding to the "EXTERNAL_STORAGE", "ANDROID_DATA" and "ANDROID_ROOT" on the line, the following is the effect of the implementation of the command line:


Figure 8-4-4 mountpoints

The several hardpoints saved to Device mMountpoints for an example of this mapping table:

67 final Map<String String>, mMountPoints new = HashMap private ();
...
783 setMountingPoint void (name String, value String) {
784 this.mMountPoints.put (name, value);
785}
Code Device setMountingPoint - 8-4-11

Note: more articles please pay attention to the public: techgogogo or personal blogHttp://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:14:34 2015/12/8Original link
Read: 121 comments: 0View comments
]]>
The most complete Pycharm tutorial (10) - Pycharm debugger Http://prog3.com/sbdm/blog/u013088062/article/details/50214459 Http://prog3.com/sbdm/blog/u013088062/article/details/50214459 U013088062 9:13:46 2015/12/8   The most complete Pycharm tutorial (1) - custom appearance

  The most complete Pycharm tutorial (2) - code style

  Most complete Pycharm tutorial (3) - code debugging, running

  The most complete Pycharm tutorial (4) - related configuration of the Python interpreter

  The most complete Pycharm tutorial (5) - Python shortcut key settings

  The most complete Pycharm tutorial (6) - Pycharm as the Vim editor

  The most complete Pycharm tutorial (7) - the configuration of virtual machine VM

  The most complete Pycharm tutorial (8) - the creation and management of Django project

  The most complete Pycharm tutorial (9) - create and run a basic Python test program

1, ready to work

(1) Pycharm version 3 or higher

(2) at least one Python interpreter is installed and configured correctly

(3) a Python project has been created

2, the main content

Describes how to debug script files through Pycharm, and the role of the various tools buttons, etc., as for the Python programming method, seeDocumentation Python.

3, to review the knowledge

In order to complete the content of this tutorial, we need to use the previous two important knowledge points:

(1) the relevant knowledge of the Run/debug configuration file

(2) the relevant knowledge of the breakpoint

4, Run/debug configuration knowledge

Whenever you run or debug a script file through Pycharm, you need a special file to record the name of the script, the working directory, and other important debug information. Pycharm has already created a configuration file for a specific pattern, which prevents us from creating it manually.

Each time you click the run or debug button (or the same operation is performed by the shortcut menu), we actually load the corresponding configuration file in the current working mode. SeeDocumentation product.

5, breakpoint

A breakpoint marked the code line, when the Pycharm runs to the code, the program will be suspended temporarily. Pycharm provides several forms of breakpointsOf breakpoints types, its iconIconNot the same. SeeProduct DocumentationInTutorial Breakpoints.

6, examples

In your Python project, create a new Python file, named ThreadSample.py, and then enter the following code:

7, set breakpoints

First, set breakpoints in the source. Generate a breakpoint at the corresponding position by clicking on the blank slot on the left side of the code:

8, start debugging

Select the configuration run/debug "ThreadSample", then press Shift+F9 (or click the green spider in the toolbar), and start debugging, and stop at the first breakpoint:

The line at which the breakpoint is located is blue, indicating that the Pycharm has hit the breakpoint, but that the code is not executed.

9, change the layout of the debug window

At this point Pycharm enter the debug interface modeTool window Debug, the specific function of each control is detailedKnow To use this tool window how.

You don't like the current default layout, for example, you want to make the debugger output window as an independent window display to more easily observe the current debug state, you can customize the layout of the.

First of all, we first put the debug tool window independently, just right click the window title bar, and then selectMode Floating:

Next will console window mobile became a separate window, just drag a console window will be the pull test window can be used to:

You can click on the toolbar.Button to revert to default layout.

For more information, seeTool Windows PyCharmAndMoving And area tabs

10, add a variable viewer

Then we describe how to observe the state of the variables in the debug process. We need to set a viewer of the. InWatchesIn the window, click the green plus, the name of the variable input expectation view, for example here to enter delay, then press enter. Of course, you can also use another way: click the variable name in the edit window right, select from the shortcut menuAdd Watches to:

At this point to observe the Watches window, found that the delay variable is not yet defined:

Later you will see how the value of the variable is negative, and the change in the watches window. We next to get_thread_name () function to set a viewer as a practice.

11, browse the frame

At this point you can see a process called MainThread, which contains three frames. Click each frame to display its variable state, and the corresponding py file, while the code line is highlighted:

12, simple debugging

Click on each breakpointButton to continue to run the program, the observation of the console script output:

13, step by step script debugging

Let's make a further test of the current script. Single clickRestart the debugging process, the program again to run to the first breakpoint and pause.

At the top of the debug window, you will see a column that contains a step into the debug button.Buttons stepping.

Single clickOr by pressing F8, you'll find the blue marker moved to the next line:

At the same time, when you pause the script execution (ClickButton), you can see the highlighted function print_time (), you can choose any of the processes, and observe the changes of the variables:

14, running to the current cursor

If you don't want to add a breakpoint, you still want the code to run to a specified code line.

Return the second breakpoint at the debug interface, insert the input cursor at the corresponding row.

Single clickButton, or press the Alt+F9 shortcut key, which is highlighted in the code:

15, how to call the Debug command

It is worth mentioning that all of the debug operation not only can be achieved through the corresponding button in the debug toolbar, but also through the main menu in the Run menu to achieve, as well as related to the shortcut menu item. Here are some common debug menu commands and their corresponding shortcut keys list:

See also more controlsTool window Debug.

Author: u013088062 was published in 9:13:46 2015/12/8Original link
Read: 118 comments: 0View comments
]]>
The 3 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - start AndroidDebugBridge Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212729 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212729 Zhubaitian 9:13:40 2015/12/8 ADB server running monkeyrunner command to execute the test script when the server may not get up, one of the main role of the AndroidDebugBridge class is to open a new process to start the ADB server, so that our test script to send commands to the ADB server to drive the target device to do things, such as installing or removing the application of the installation package, etc..

MonkeyRunner involves a series of calls and related to different classes to do different things.


Figure 8-3-1 the class relationship involved in AndroidDebugBridge

The above class diagram lists the key classes involved in starting the AndroidDebugBridge, and lists the key member methods and member variables for each class of design during the boot process:

  • MonkeyRunnerStarter: this class we have encountered in the last section, it is the jar monkeyrunner package entrance class. It has the options object we have analyzed. This section we mainly analyze is a series of calls from the monkeyRunnerStarter constructor to start AndroidDebugBridge as the target. In the process, it will be an instance of the ChimpChat, and the instance of the MonkeyRunner is saved by setChimpChat's method to the chimpchat's MonkeyRunner. What's the use of it? We should note that MonkeyRunner, ChimpChat and AdbBackend have the waitForConnection method, the method is generally in our test script at the beginning of the call, the purpose is to get a high level of abstraction device called AdbChimpDevice object, this we start Monkey in the sixth section will be described in detail. Here we are mainly to illustrate the MonkeyRunner after the preservation of the ChimpChat instance, its waitForConnection method will be able to directly call the waitForConnection method by ChimpChat chimpchat.
  • The main function of ChimpChat: is to combine the AdbBackend to create the AndroidDebugBridge. MonkeyRunnerStarter relies on this class to create an instance of the AdbBackend class and save it to the mBackend of the class. The purpose of saving is to use the waitForConnection method to call the waitForConnection method of the AdbBackend class for the purpose of the MonkeyRunner ChimpChat.
  • AdbBackend: is responsible for creating an instance of AndroidDebugBridge. It will create an instance of AndroidDebugBridge and save it to the bridge member variable, so long as you have the AdbBackend instance of the bridge to get the latest AndroidDebugBridge maintenance list. Such as AdbBackend in the implementation of the waitForConnection method to call the bridge.getDevices method to obtain all the connected device list, and then through the device serial number to find the target device to connect
  • AndroidDebugBridge: this class has two important functions, one is to start the ADB server, and the other is to start the device monitoring thread DeviceMonitor. Second points we will be in the next section, we will focus on the analysis of the first point of view how it is to start the ADB server. See that they are mainly is to start the ADB server, such as default ADB host and default ADB port variables mainly specifies the ADB server default to listen to the address and port, getAdbLaunchCommand is to obtain corresponding ADB start or stop command string to start the ADB server (open innovation process, "the ADB start-server" or stop the ADB server (ADB kill-server ") from the above list of the class member variables and methods can

Here we explain the principle through the source analysis. After a good command line argument is processed by the last section, the next step is to try to invoke the constructor of the monkeyrunner with the main function:

178 static void main public (args String[]) {
179 options MonkeyRunnerOptions =
MonkeyRunnerOptions.processOptions (args);
180
181 If (options = = null) {
182 return;
183}
184
185
186 replaceAllLogFormatters (MonkeyFormatter.DEFAULT_INSTANCE,
Options.getLogLevel ());
187
188 runner MonkeyRunnerStarter =
MonkeyRunnerStarter new (options);
189 error int = runner.run ();
190
191
192 System.exit (error);
193}
194}
8-3-1 code MonkeyRunnerStarter

The options parameter is the last section of the MonkeyRunnerOptions object, which holds all the parameters. Down we go into the MonkeyRunnerStarter constructor:

55 MonkeyRunnerStarter public (options MonkeyRunnerOptions)
{56
57 Map<String, chimp_options new = TreeMap String> ();
58 chimp_options.put ("backend", options.getBackendName ());
59 this.options = options;
60 this.chimp = ChimpChat.getInstance (chimp_options);
61 MonkeyRunner.setChimpChat (this.chimp);
62}
Code MonkeyRunnerStarter 8-3-2 constructor

Only a few lines of code from this method we can see that it is actually doing the thing is to initialize the ChimpChat and the MonkeyRunnerStarter of the chimp of the backend member variable, but also call the static method MonkeyRunner ChimpChat the setChimpChat object is set to the static member variables of the MonkeyRunner, why should it be a static member variable? Because the sixty-first line holds the instance call is the method of MonkeyRunner, and is not an instance, so the method must be static, and a static method in which the member function is also bound to be static. We jump into the MonkeyRunner class to see:

51 void setChimpChat static (chimp ChimpChat)
{52
53 chimpchat = chimp;
54}
Code MonkeyRunner setChimpChat - 8-3-3

We return to continue to see how ChimpChat is started, first of all we MonkeyRunnerStarter constructor fifty-eighth line optionsGetBackendName () is how to get the name of backend, from the last section of the command line parameters analysis we can know that it is the default is' ADB ', so it is' ADB', or user specified backend (in fact, this situation is not supported, we will continue to analyze).

After the name of the backend will call the 60 line of ChimpChat.getInstance to the ChimpChat to be a:

46 static ChimpChat getInstance public (Map<String, options String>)
{47
48 sAdbLocation = (String) options.get ("adbLocation");
49 sNoInitAdb = Boolean.valueOf ((String) options.get ("noInitAdb")).BooleanValue ();
50
51 backend IChimpBackend = createBackendByName ((String) options.get ("backend"));
52如果(后端=空){
53返回空;
54 }
55 chimpchat chimpchat =新chimpchat(后台);
56回chimpchat;
57 }

代码8-3-4 chimpchat - getInstance

chimpchat实例化所做的事情有两点,这也就是我们这一小节的重点所在了:

  • 根据后端的名字来创建一个后端,其实就是创建一个androiddebugbridge亚行
  • 调用构造函数把这个后端保存到chimchat的成员变量

往下我们继续看chimpchat中androiddebugbridge这个后端是怎么创建的,我们进入到51行调用的createbackendbyname这个函数:

75私有静态ichimpbackend createbackendbyname(字符串backendname)
76 {
77如果(“亚行”。等于(backendname)){
78回新adbbackend(sadblocation,snoinitadb);
79 }
80返回空;
81 }
代码8-3-5 chimpchat - createbackendbyname

这里注意第77行,这就是为什么我之前说后端其实只是支持'adb”而已,起码暂时的代码是这样子,如果今后谷歌决定支持其他更新的后端,就另当别论了。这还是有可能的,毕竟谷歌留了这个接口。

56公共adbbackend(字符串adblocation,布尔noinitadb)
57 {
58 this.initadb =(!noinitadb);
59
60
61如果(adblocation = = null){
62 adblocation = findadb();
63 }
64
65如果(这。initadb){
66 androiddebugbridge init(假);
67 }
68
69 this.bridge = androiddebugbridge createbridge(adblocation,真的);
70 }
代码8-3-6 adbbackend构造函数

创建androiddebugbridge之前我们先要确定我们的亚行程序的位置,这就是通过62行来实现的,我们进去findadb去看下它是怎么找到我们的SDK中的亚行的:

72 findadb()字符串
73 {
74弦mrparentlocation =
系统。getProperty(“COM。Android。monkeyrunner。BINDIR”);
75
76
77
78
79
80如果((mrparentlocation!= null)和(mrparentlocation。length()!= 0)
81 {
82文件platformtools =新的文件(新
文件(mrparentlocation getparent()),
“平台工具”);
83
84如果(platformtools。isdirectory()){
85回platformtools getabsolutepath() file.separator + +。
sdkconstants.fn_adb;
86 }
87
88回mrparentlocation file.separator + +
sdkconstants.fn_adb;
89 }
90
91回sdkconstants.fn_adb;
92 }
代码8-3-7 adbbackend - findadb

首先它通过查找JVM中的系统性能来找到“COM。Android。monkeyrunner。BINDIR”这个属性的值,记得前面小节运行环境初始化的时候在monkeyrunner这个壳脚本里面它是怎么通过Java的D参数把该值保存到JVM里面的吧?其实它就是你的文件系统中保存SDK的monkeyrunner这个箱(壳)文件的路径,在我的机器上是“COM。Android。monkeyrunner。BINDIR:/用户/苹果/开发/开发/工具”。

找到这个路径后通过第82行的代码再取得它的父目录,也就是SDK的目录,再加上'platform-tools”这个子目录,然后再通过85或者88这行加上亚行这个名字,这里的fn_adb就是亚行的名字,在Windows下会加上个“.exe”变成'adb .exe”,类Linux系统下就只是'adb’。在本人的机器里面就是“用户/苹果/开发/ SDK平台/工具/亚行”

好,找到了亚行所在路经后,adbbackend的构造函数就会根据这个参数去调用androiddebugbridge的createbridge这个静态方法:

265公共静态androiddebugbridge createbridge()
…
271试
272 {
273这=新androiddebugbridge();
274 start()这;
275 } catch(invalidparameterexception e){
276这= null;
277 }
…
297回本;
298 }
299 }
代码8-3-8 androiddebugbridge - createbridge

第273行androiddebugbridge的构造函数做的事情就是实例化androiddebugbridge,亚行真正启动起来是调用274行的start()这个成员方法:

713布尔start()
714 {
715如果((this.madboslocation!=空)&
(sadbserverport!= 0)&
((!这mversioncheck | |()!startadb()))){
716返回假;
717 }
718
719 this.mstarted =真;
720
721
722 this.mdevicemonitor =新设备显示器(本);
723本。mdevicemonitor。start();
724
725返回真实;
726 }
代码8-3-9 androiddebugbridge启动

这里做了几个很重要的事情:

  1. 715行startadb:开启androiddebugbridge
  2. 722-723行:初始化设备监控并启动设备监控线程Android设备显示器。

这一小节我们先看第一个startadb,看它是如何把androiddebugbridge给开启起来的,第2点我们将会在下一小节描述。

943同步布尔startadb()
944 {
945如果(this.madboslocation = = null){
946日志。E(“亚行”、“无法启动亚行在androiddebugbridge创建没有位置亚行”。);
947
948返回假;
949 }
950
951如果(sadbserverport = = 0){
952日志。W(“亚行”、“亚行服务器端口启动androiddebugbridge未设置”。);
953返回假;
954 }
955
956
957国际地位= - 1;
958
959弦[ ]命令= getadblaunchcommand(“启动服务器”);
960弦commandstring =木工,(',')加入(命令);
961尝试{
962日志。D(“摘要”,字符串。格式(“发射”1元的“确保亚行正在运行。”新对象[ ] { commandstring }));
963 processbuilder processbuilder =新processbuilder(命令);
964如果(ddmpreferences。getuseadbhost()){
965 adbhostvalue = ddmpreferences getadbhostvalue()字符串;
966如果((adbhostvalue!=空)&(!adbhostvalue isempty()))。
967 {
968地图<字符串,字符串> processbuilder environment() env =;
969环境。把(“adbhost”,adbhostvalue);
970 }
971 }
972工艺过程processbuilder start() =;
973
974 ArrayList <字符串>误差输出=新arraylist();
975 ArrayList <字符串>程序=新arraylist();
976状态= grabprocessoutput(过程、误差输出,程序,假);
977 } catch(IOException IOE){
978日志。E(“资讯”、“无法运行“亚行”:“+“IOE”。getmessage());
979 }
980抓(InterruptedException IE){
981日志。E(“资讯”、“无法运行“亚行”:即“+ getmessage());
982 }
983
984
985如果(身份!= 0){
986日志。E(“摘要”,字符串格式(“% 1 $的失败——手动运行时”,新的对象[ ] { commandstring }));
987
988返回假;
989 }
990日志。D(“摘要”,字符串格式(“% 1美元的“成功”,新的对象[ ] { commandstring }));
991返回真实;
992 }
代码8-3-10 androiddebugbridge - startadb

这里所做的事情就是:

  • 准备好启动DB服务器的命令字串
  • 通过processbuilder启动命令字串指定的adb服务器
  • 错误处理

命令字串通过959行的getadblaunchercommand('start-server”)来实现:

994 [ ] getadblaunchcommand字符串(字符串选项)
995 {
996表<字符串>命令=新的列表(4);
997命令。添加(这个。madboslocation);
998如果(sadbserverport!= 5037){
999命令。(“-”);
1000命令。添加(整数。toString(sadbserverport));
1001 }
1002命令(选项);
1003回(string [])命令。toArray(新的字符串[命令。size() ]);
1004 }
代码8-3-11 androiddebugbridge - getadblaunchcommand

整个函数玩的就是字串组合,最后获得的字串就是“亚行- P $港启动服务器”,也就是开启亚行服务器的命令行字串了,最终把这个字串打散成字串数组返回这里注意默认值就是亚行服务器的默认监听端口5037端口。

startadb方法获得命令之后下一步就是直接调用Java的processbuilder构造函数来创建一个亚行服务器进程了。创建好后就可以通过972行的'processbuilder把这个进程启动起来start()”。

迄今为止androiddebugbridge启动函数start()所做事情的第一点”1。启动androiddebugbridge”已经完成了,亚行服务器进程已经运行起来了。

注:更多文章请关注公众号:techgogogo或个人博客http://techgogogo.com. Of course, also welcome you directly to the micro channel (zhubaitian1). The original Zhuhai triad operation. Reproduced please consciously, whether the right to complain about the mood.


Author: zhubaitian was published in 9:13:40 2015/12/8Original link
Read: 126 comments: 0View comments
]]>
The 2 chapter of the eighth section "MonkeyRunner source analysis" MonkeyRunner start running process - Analysis of the command line parameters Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212717 Http://prog3.com/sbdm/blog/zhubaitian/article/details/50212717 Zhubaitian 9:13:01 2015/12/8 MonkeyRunnerStarter is the entry class for the MonkeyRunner boot, because it contains the main method:

  • The parameters that the user starts MonkeyRunner from the command lineBecause MonkeyRunner needs to do things according to the specified parameters, such as the input of a need to execute the script. If you do not know any parameters, then it will enter the interactive mode of MonkeyRunner, in fact, is the interactive mode of Jythong, so that the user can write code while performing
  • Start AndroidDebugBridge: in fact, is to start the ADB server, because the MonkeyRunner with a very important way to communicate with the device is to send commands to the ADB server to request the service of the target device
  • Boot device monitor thread: in fact, this is the start of the AndroidDebugBridge in conjunction with the start. Equipment monitoring thread is mainly to do the access to the monitoring device is connected or removed, if there is a new device to connect in, or the device into a ONLINE state (a device has a number of states: ONLINE|OFFLINE|RECOVERY|UNAUTHORIZED), then it is necessary to monitor each of the devices in the debug process, which is mainly used for DDMS and other debugging tools. It maintains a list of the latest devices
  • Start AndroidDebugBridge:
  • Start Monkey:
  • Run test script:

In this section, we'll look at how the MonkeyRunner is obtained from the command line parameters and then the analytical processing. The whole process is similar to the monkey command line parameter analysis at startup. We first look at the relationship between the key classes involved: