Android深入理解分析Aidl調(diào)用流程_劉永雷_2017.2.3_第1頁(yè)
Android深入理解分析Aidl調(diào)用流程_劉永雷_2017.2.3_第2頁(yè)
Android深入理解分析Aidl調(diào)用流程_劉永雷_2017.2.3_第3頁(yè)
Android深入理解分析Aidl調(diào)用流程_劉永雷_2017.2.3_第4頁(yè)
Android深入理解分析Aidl調(diào)用流程_劉永雷_2017.2.3_第5頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、Android深入理解分析Aidl調(diào)用流程2017年開始上班的第一天,老不想工作了,假期感覺還沒開始就已經(jīng)結(jié)束了,唉,時(shí)間就是這樣,新的一年開始了,雖然很不想干正事,沒辦法,必須干起來,因?yàn)楹筮叺穆愤€很長(zhǎng),距離六十歲還很遠(yuǎn)。剛上班也沒什么事,復(fù)習(xí)一下之前的東西,看了一下Aidl相關(guān)的知識(shí),仔細(xì)瞅了瞅Aidl的調(diào)用流程,這里寫篇文章整理一下,幫助大家的同時(shí),自己也加深一下印象。對(duì)Aidl不太了解的童鞋可以先看一下我之前的一篇文章,鏈接如下: 案例下載鏈接: 。在上篇文章中我們已經(jīng)說過了Android中Aidl的簡(jiǎn)單應(yīng)用及對(duì)象的傳遞方式,還包含了在AS中進(jìn)行Aidl開發(fā)會(huì)遇到的一些問題及決解方法,

2、本篇文章針對(duì)使用方法我們不在多說,我們將以傳遞對(duì)象為例深入的剖析Aidl的詳細(xì)調(diào)用流程,繼續(xù)以上文中傳遞Person對(duì)象為例展開,通過本片文章的學(xué)習(xí)你會(huì)學(xué)到以下相關(guān)知識(shí):1.Aidl工作調(diào)用流程;2.Aidl傳遞對(duì)象時(shí)修飾符in、out、inout的深入理解。3.對(duì)實(shí)現(xiàn)Parcelable接口對(duì)象中需要實(shí)現(xiàn)方法的深入理解。首先看一下我們要傳遞對(duì)象的代碼:public class Person implements Parcelable private String name; private int age; public Person() protected Person(Parcel in

3、) name = in.readString(); age = in.readInt(); public static final Creator<Person> CREATOR = new Creator<Person>() Override public Person createFromParcel(Parcel in) return new Person(in); Override public Person newArray(int size) return new Personsize; ; public String getName() return na

4、me; public void setName(String name) = name; public int getAge() return age; public void setAge(int age) this.age = age; Override public int describeContents() return 0; Override public void writeToParcel(Parcel dest, int flags) dest.writeString(name); dest.writeInt(age); public void readF

5、romParcel(Parcel dest) name = dest.readString(); age = dest.readInt(); Override public String toString() return "Person" + "name='" + name + ''' + ", age=" + age + '' Person類實(shí)現(xiàn)了parcelable接口,有兩個(gè)構(gòu)造方法,有name、age兩個(gè)成員變量,編譯器可以幫我們生成一個(gè)static、final的CREATOR

6、跟writeToParcel()方法,我們自己寫readFromParcel()方法,這里切記順序要與writeToParcel()方法一直。 下邊再看一下我們的.aidl文件代碼:import com.jason.aidl.aidldemo.Person;interface IMyAidlInterface String inPerson(in Person p); String outPerson(out Person p); String inOutPerson(inout Person p);這里需要注意我們的Person也需要寫對(duì)應(yīng)的Person.aidl文件,并在build.gra

7、dle中配置,詳細(xì)信息就不介紹了,上篇文章中進(jìn)行了詳細(xì)講解,在這里看到了修飾符in、out、inout,后文會(huì)做詳細(xì)講解。我們繼續(xù)看Aidl文件生成對(duì)應(yīng)的.java文件的一個(gè)整體架構(gòu)??s略代碼如下:public interface IMyAidlInterface extends android.os.IInterface /* * Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.jason.aidl.a

8、idldemo.IMyAidlInterface private static final java.lang.String DESCRIPTOR = "com.jason.aidl.aidldemo.IMyAidlInterface" /* * Construct the stub at attach it to the interface. */ public Stub() this.attachInterface(this, DESCRIPTOR); /* * Cast an IBinder object into an com.jason.aidl.aidldemo

9、.IMyAidlInterface interface, * generating a proxy if needed. */ public static com.jason.aidl.aidldemo.IMyAidlInterface asInterface(android.os.IBinder obj) /. Override public android.os.IBinder asBinder() return this; Override public boolean onTransact(int code, android.os.Parcel data, android.os.Par

10、cel reply, int flags) throws android.os.RemoteException /. return super.onTransact(code, data, reply, flags); private static class Proxy implements com.jason.aidl.aidldemo.IMyAidlInterface private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) mRemote = remote; Override public android.

11、os.IBinder asBinder() return mRemote; public java.lang.String getInterfaceDescriptor() return DESCRIPTOR; Override public java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException /. return _result; Override public java.lang.String outPerson(com.jason.aidl.aidldem

12、o.Person p) throws android.os.RemoteException /. return _result; Override public java.lang.String inOutPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException /. return _result; static final int TRANSACTION_inPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final i

13、nt TRANSACTION_outPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1); static final int TRANSACTION_inOutPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2); public java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException; public java.lang.String outPer

14、son(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException; public java.lang.String inOutPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException;大致分為三部分,一個(gè)interface(最外層的類)兩個(gè)內(nèi)部類(Stub、Proxy),先看interface,它跟我們定義的.aidl文件名字相同,繼承了IInterface,它的內(nèi)容分為兩部分:一個(gè)內(nèi)部類Stub及我們定義的Person抽象操

15、作方法,每一個(gè)都拋出RemoteException。接下來看他的內(nèi)部類Stub,它是一個(gè)抽象類,繼承了Binder類,實(shí)現(xiàn)了外層的Interface,他比較重要的是一個(gè)asInterface()方法和onTransact()方法,它還有一個(gè)static的內(nèi)部類Proxy,它也實(shí)現(xiàn)了最外層的Interface,另外有一個(gè)需要傳遞Ibinder的構(gòu)造函數(shù),還有就是與我們?cè)贏idl類中定義的方法名稱相同的方法。這就是我們生成的.java文件的一個(gè)大致的架構(gòu)。由上邊可知最外層Interface是IInterface的子類,而Stub與Proxy是最外層Interface的實(shí)現(xiàn)類,Stub繼承了Bind

16、er,他們之間存在這樣的關(guān)系。下面我們就對(duì)代碼的調(diào)用流程進(jìn)行詳細(xì)講解。首先我們?cè)趹?yīng)用Aidl時(shí)通過客戶端綁定的方式來獲取我們的IMyAidlInterface,并通過它來調(diào)用服務(wù)端的方法進(jìn)行通信,如下代碼:private IMyAidlInterface mService;Intent intent = new Intent();intent.setAction("com.lyl.aidl");Intent intent1 = new Intent(createExplicitFromImplicitIntent(this, intent);/兼容5.0以后版本bindSe

17、rvice(intent1, mServiceC, Context.BIND_AUTO_CREATE);ServiceConnection mServiceC = new ServiceConnection() Override public void onServiceConnected(ComponentName name, IBinder service) mService = IMyAidlInterface.Stub.asInterface(service); Override public void onServiceDisconnected(ComponentName name)

18、 ;public void do(View v) try Person p1 = new Person(); p1.setName("劉大"); p1.setAge(3); Person p2 = new Person(); p2.setName("趙二"); p2.setAge(3); Person p3 = new Person(); p3.setName("張三"); p3.setAge(3); tv.setText("" + mService.inPerson(p1) + "n" + m

19、Service.outPerson(p2) + "n" + mService.inOutPerson(p3); catch (RemoteException e) e.printStackTrace(); 上邊代碼通過IMyAidlInterface.Stub.asInterface(service)獲取了我們的IMyAidlInterface,do()方法中通過它才調(diào)用了我們服務(wù)端的代碼,那我們先看一下這個(gè)asInterface方法中的參數(shù)是什么,我們知道當(dāng)通過綁定的方式獲取的binder是我們?cè)诜?wù)中的onBind()方法中返回的,看一下我們服務(wù)端的代碼:public

20、class MyAidlService extends Service Override public int onStartCommand(Intent intent, int flags, int startId) Log.i("Log_LYL", "Onstart"); return super.onStartCommand(intent, flags, startId); Override public IBinder onBind(Intent intent) return stub; IMyAidlInterface.Stub stub =

21、new IMyAidlInterface.Stub() Override public String inPerson(Person p) throws RemoteException . Override public String outPerson(Person p) throws RemoteException . Override public String inOutPerson(Person p) throws RemoteException . ;通過以上服務(wù)端代碼可以知道我們返回的是一個(gè)stub 事例,而它是我們的.aidl文件自動(dòng)生成的.java文件中Stub的一個(gè)實(shí)例對(duì)象

22、?,F(xiàn)在我們知道IMyAidlInterface.Stub.asInterface(service)中的service是編譯器為我們生成的.java文件的一個(gè)實(shí)例。我們接著看IMyAidlInterface中Stub.asInterface(service)方法,代碼如下:public static com.jason.aidl.aidldemo.IMyAidlInterface asInterface(android.os.IBinder obj) if (obj = null) return null; android.os.IInterface iin = obj.queryLocalIn

23、terface(DESCRIPTOR); if (iin != null) && (iin instanceof com.jason.aidl.aidldemo.IMyAidlInterface) return (com.jason.aidl.aidldemo.IMyAidlInterface) iin); return new com.jason.aidl.aidldemo.IMyAidlInterface.Stub.Proxy(obj);因?yàn)槲覀兊腟tub類繼承了Binder,Binder實(shí)現(xiàn)了Ibinder接口,所以傳遞Stub的實(shí)例在這里沒問題。上述代碼首先判斷了obj

24、是否為空,不為空往下走,第二個(gè)if判斷是在判斷通過obj獲取的iin是否屬于當(dāng)前程序運(yùn)行的進(jìn)程,如果是,直接返回,這里也就是說我們要調(diào)用的服務(wù)與我們當(dāng)前程序在同一進(jìn)程,不需要遠(yuǎn)程通信,直接調(diào)用就行。如果不是可以看見系統(tǒng)新生成了一個(gè)Proxy對(duì)象實(shí)例,并把我們的stub實(shí)例對(duì)象傳遞進(jìn)去,看一下Proxy的構(gòu)造函數(shù),代碼如下:private android.os.IBinder mRemote;Proxy(android.os.IBinder remote) mRemote = remote;可以看到通過構(gòu)造函數(shù)將Stub實(shí)例又一次傳到了Proxy中并賦值給mRemote,mRemote也變成了S

25、tub實(shí)例。到這里綁定服務(wù)獲取ImyAidlInterface對(duì)象就介紹完了,做一下總結(jié):通過綁定的方式獲取到了在服務(wù)端的系統(tǒng)生成的.aidl文件對(duì)應(yīng)的.java文件中子類Stub的一個(gè)實(shí)例,調(diào)用Stub類中的asInterface()方法判斷Stub實(shí)例所在進(jìn)程與當(dāng)前進(jìn)程是否為同一個(gè),是直接可以操作,不是生成一個(gè)Proxy實(shí)例并將Stub傳入。下面我們看一下調(diào)用代碼實(shí)現(xiàn):public void do(View v) try Person p1 = new Person(); p1.setName("劉大"); p1.setAge(3); Person p2 = new P

26、erson(); p2.setName("趙二"); p2.setAge(3); Person p3 = new Person(); p3.setName("張三"); p3.setAge(3); tv.setText("" + mService.inPerson(p1) + "n" + mService.outPerson(p2) + "n" + mService.inOutPerson(p3); catch (RemoteException e) e.printStackTrace(); 我

27、們首先分析第一個(gè)inPerson(p1);這個(gè)方法我們?cè)诙x時(shí)的修飾符為in,及String inPerson(in Person p);下邊我們看一下它的實(shí)現(xiàn)過程,通過上邊的介紹可以知道m(xù)Service如果不是在同一個(gè)進(jìn)程中是返回的Proxy對(duì)象實(shí)例,那么我們就進(jìn)入Proxy中查找對(duì)應(yīng)的方法,代碼如下:Overridepublic java.lang.String inPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException android.os.Parcel _data = android.os.P

28、arcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); java.lang.String _result; try _data.writeInterfaceToken(DESCRIPTOR); if (p != null) _data.writeInt(1); p.writeToParcel(_data, 0); else _data.writeInt(0); mRemote.transact(Stub.TRANSACTION_inPerson, _data, _reply, 0); _reply.readE

29、xception(); _result = _reply.readString(); finally _reply.recycle(); _data.recycle(); return _result;可以看到系統(tǒng)生成了_data、_reply兩個(gè)Parcel類型的對(duì)象,然后操作_data,寫入Token,判斷如果傳入的Person對(duì)象不為空寫入了一個(gè)1,接下來調(diào)用了person類的writeToParcel()方法,傳入了_data,咦,注意這里,我們就知道了實(shí)現(xiàn)Parcelable接口時(shí)的writeToParcel()方法在這里會(huì)用到。好的,我們跟進(jìn)看一下,代碼如下:Overridepub

30、lic void writeToParcel(Parcel dest, int flags) dest.writeString(name); dest.writeInt(age);這一步看來就是給_data賦值,將我們從開始調(diào)用inPerson(com.jason.aidl.aidldemo.Person p) p實(shí)例中的值以writeString、writeInt的方式保存到_data中,如果傳入的p為null則寫入一個(gè)0。繼續(xù)往下走,我標(biāo)紅的那句是重點(diǎn),也是這句進(jìn)行了binder通信,關(guān)于binder通訊機(jī)制有很多很多東西,由于本人能力有限在這里就不多講了,感興趣的可以去了解一下。通過前邊

31、可以知道m(xù)Remote為asInterface方法傳入的service,及Stub實(shí)例,而Stub中根本沒有transact()方法,而它是Binder的子類,好,我們?nèi)inder中找,還真有:public final boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException if (false) Log.v("Binder", "Transact: " + code + " to " + this); if (da

32、ta != null) data.setDataPosition(0); boolean r = onTransact(code, data, reply, flags); if (reply != null) reply.setDataPosition(0); return r;可以看到,在這里調(diào)用了onTransact(code, data, reply, flags);我們知道在Stub類中我們實(shí)現(xiàn)了這個(gè)方法,我們看一下Stub類中的這個(gè)方法:Overridepublic boolean onTransact(int code, android.os.Parcel data, andro

33、id.os.Parcel reply, int flags) throws android.os.RemoteException switch (code) case INTERFACE_TRANSACTION: reply.writeString(DESCRIPTOR); return true; case TRANSACTION_inPerson: data.enforceInterface(DESCRIPTOR); com.jason.aidl.aidldemo.Person _arg0; if (0 != data.readInt() _arg0 = com.jason.aidl.ai

34、dldemo.Person.CREATOR.createFromParcel(data); else _arg0 = null; java.lang.String _result = this.inPerson(_arg0); reply.writeNoException(); reply.writeString(_result); return true; return super.onTransact(code, data, reply, flags);在這里我們只摘取了inPerson()方法相關(guān)內(nèi)容,先了解一下傳入的四個(gè)參數(shù):1.code 每一個(gè)方法對(duì)應(yīng)一個(gè)code,我們定義了多少方法

35、就會(huì)有多少code,通過它來做不同處理;2.data、reply為在proxy對(duì)應(yīng)方法中生成的兩個(gè)Parcel對(duì)象;3.flags 一般為1,這個(gè)不用管先。 首先通過code找到對(duì)應(yīng)方法的操作,判斷data中寫入的int值是否為0,不為0說明之前的p不為null,并且已經(jīng)存入到data中,調(diào)用Person中的CREATOR的createFromParcel()方法,咦,這里又用到了Parcelable的東西??匆幌逻@個(gè)方法:public static final Creator<Person> CREATOR = new Creator<Person>() Overri

36、de public Person createFromParcel(Parcel in) return new Person(in); Override public Person newArray(int size) return new Personsize; ;protected Person(Parcel in) name = in.readString(); age = in.readInt();可以看到,系統(tǒng)在這里創(chuàng)建了一個(gè)Person實(shí)例,傳入了我們之前的data(保存有person信息),并將data中的信息賦值給新的person對(duì)象?;氐絊tub類的onTransace()方

37、法中繼續(xù)往下看:java.lang.String _result = this.inPerson(_arg0);reply.writeNoException();reply.writeString(_result);return true;接著系統(tǒng)調(diào)用了this.inPerson(_arg0)方法,_arg0為上邊通過createFromParcel()方法新生成的person(包含傳遞過來的person值)對(duì)象,我們知道Stub為抽象類,他實(shí)現(xiàn)了我們外層的Interface類,但是沒有實(shí)現(xiàn)inPerson()方法,那么我們就需要它的子類實(shí)現(xiàn),而我們的mRemote.transace()中的m

38、Remote就是服務(wù)端返回的Stub的一個(gè)實(shí)現(xiàn)子類,也就是說這里調(diào)用的this.inPerson(_arg0)方法實(shí)際是調(diào)用了服務(wù)端的那個(gè)Stub實(shí)現(xiàn)類里邊的inPerson()方法,看一下我們之前服務(wù)端的inPerson()方法的具體實(shí)現(xiàn):Overridepublic String inPerson(Person p) throws RemoteException String old = "name:" + p.getName() + " age:" + p.getAge(); Log.d("Log_LYL:iPerson_",

39、old); p.setName("李四"); p.setAge(13); return "name:" + p.getName() + " age:" + p.getAge();通過以上分析,大家就知道了這里的 Log.d("Log_LYL:iPerson_", old); 是為什么有值了,因?yàn)槲覀円婚_始就將傳入的person值附到了Parcel類型的data中了,然后又通過createFromParcel()方法將data中的值付給了新的person對(duì)象。 然后回到Stub類的onTransace()方法,會(huì)看到

40、調(diào)用了reply.writeNoException();reply.writeString(_result);兩個(gè)方法,將服務(wù)端處理完后返回的信息寫入了reply中。最后return。再回到Proxy類中的inPerson()方法中: mRemote.transact(Stub.TRANSACTION_inPerson, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); finally _reply.recycle(); _data.recycle();return _result;將服務(wù)端返回的

41、信息讀出來并付給_result,最后返回,這樣我們?cè)赼ctivity中就可以得到服務(wù)端處理后的結(jié)果了,到現(xiàn)在為止,我們就應(yīng)該明白了,通過in修飾符傳遞person后服務(wù)端生成了新的person對(duì)象,并對(duì)新person對(duì)象進(jìn)行處理,這樣的話無(wú)論服務(wù)端如何修改person對(duì)象我們客戶端的person對(duì)象是不會(huì)受任何影響的,為什么,因?yàn)椴皇且粋€(gè)對(duì)象。這就是in操作符。下面我們分析一下out操作符,直接看代碼:String outPerson(out Person p);/.aidl文件中定義;mService.outPerson(p2)/客戶端調(diào)用;我們?cè)诳蛻舳酥苯油ㄟ^綁定時(shí)返回的Stub實(shí)例調(diào)用o

42、utPerson()方法,通過上邊對(duì)inPerson()方法的介紹我們知道不是同一個(gè)進(jìn)程中的會(huì)最終調(diào)用到Proxy中相應(yīng)的方法中,那我們直接看Proxy中代碼:Overridepublic java.lang.String outPerson(com.jason.aidl.aidldemo.Person p) throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); j

43、ava.lang.String _result; try _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); if (0 != _reply.readInt() p.readFromParcel(_reply); finally _reply.recycle(); _data.recycle(); return _result;有了上

44、邊對(duì)inPerson()方法的了解這個(gè)相對(duì)就簡(jiǎn)單多了,同樣生成兩個(gè)Parcel對(duì)象,作用相同,不同的是用out修飾后沒有對(duì)傳入的p做null判斷,也沒有取值保存到data中,而是直接調(diào)用了mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0)方法,那好,通過前邊我們直接去Stub中找onTransact()方法吧:case TRANSACTION_outPerson: data.enforceInterface(DESCRIPTOR); com.jason.aidl.aidldemo.Person _arg0; _arg0

45、= new com.jason.aidl.aidldemo.Person(); java.lang.String _result = this.outPerson(_arg0); reply.writeNoException(); reply.writeString(_result); if (_arg0 != null) reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); else reply.writeInt(0); return true;我

46、們只要out方法相關(guān)信息,這里系統(tǒng)通過new Person()的方式創(chuàng)建了一個(gè)person對(duì)象實(shí)例賦值個(gè)_arg0,這個(gè)對(duì)象與我們調(diào)用時(shí)傳進(jìn)來的對(duì)象沒有一點(diǎn)關(guān)系,然后直接調(diào)用了this.outPerson()方法,通過inPerson()的介紹我們就知道這里直接調(diào)用了服務(wù)端outPerson()實(shí)現(xiàn):Overridepublic String outPerson(Person p) throws RemoteException /這里的p是空的,因?yàn)樵贗MyAidlInterface的Stub類中onTransact()方法中沒有寫入; / _arg0 = new com.jason.aidl

47、.aidldemo.Person(); /java.lang.String _result = this.outPerson(_arg0); String old = "name:" + p.getName() + " age:" + p.getAge(); Log.d("Log_LYL:outPerson_", old); p.setName("周六"); p.setAge(20); return "name:" + p.getName() + " age:" + p.ge

48、tAge();這里可以知道old是沒有賦值的,下面賦值return,回到Stub中:java.lang.String _result = this.outPerson(_arg0);reply.writeNoException();reply.writeString(_result);if (_arg0 != null) reply.writeInt(1); _arg0.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE); else reply.writeInt(0);return true;將處理

49、結(jié)果寫入reply中,判斷_arg0是否為null,不是,寫入1,這里又一次用到了writeToParcel()方法,通過上邊inPerson()方法介紹可知這里是將_arg0的值付給reply;如果為null,reply中賦值0?;氐絇roxy中:try _data.writeInterfaceToken(DESCRIPTOR); mRemote.transact(Stub.TRANSACTION_outPerson, _data, _reply, 0); _reply.readException(); _result = _reply.readString(); if (0 != _reply.readInt() p.readFromParcel(_reply); finally _reply.recycle(); _data.recycle();return _result;執(zhí)行完transact()方法后從_reply中讀出服務(wù)端操作返回結(jié)果,判斷寫入的int值,如果不為0,說明_reply中寫入了服務(wù)端產(chǎn)生的person信息,則將通過readFromParcel()方法將新的_reply中保存的服務(wù)端的person信息寫入到客戶端傳入的p中,這樣客戶端就收到了服務(wù)端的person信息。總結(jié)一下o

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論