Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

上传人:痛*** 文档编号:84155436 上传时间:2022-05-03 格式:DOC 页数:46 大小:766.50KB
收藏 版权申诉 举报 下载
Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_第1页
第1页 / 共46页
Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_第2页
第2页 / 共46页
Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析_第3页
第3页 / 共46页
资源描述:

《Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析》由会员分享,可在线阅读,更多相关《Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析(46页珍藏版)》请在装配图网上搜索。

1、在前面几篇文章中,我们详细介绍了 An droid系统进程间通信机制 Binder的 原理,并且深入分析了系统提供的 Binder运行库和驱动程序的源代码。细心的读者 会发现,这几篇文章分析的Binder接口都是基于C/C+语言来实现的,但是我们在 编写应用程序都是基于Java语言的,那么,我们如何使用 Java语言来使用系统的 Bin der机制来进行进程间通信呢?这就是本文要介绍的 An droid系统应用程序框架 层的用Java语言来实现的Binder接口了。熟悉An droid系统的读者,应该能想到应用程序框架中的基于Java语言的Binder接口是通过JNI来调用基于C/C+语言的B

2、inder运行库来为Java应用程序提供进程间通信服务的了。 JNI在An droid系统中用得相当普遍,SDK中的Java 接口 API很多只是简单地通过JNI来调用底层的C/C+运行库从而为应用程序服务 的。这里,我们仍然是通过具体的例子来说明Binder机制在应用程序框架层中的Java接口,主要就是 Service Manager、Server和Client这三个角色的实现了。通 常,在应用程序中,我们都是把Server实现为Service的形式,并且通过IServiceManager.addService接口来把这个 Service 添加到 Service Manager ,Clien

3、t 也是通过 IServiceManager.getService 接口来获得 Service 接口,接着就可 以使用这个Service提供的功能了,这个与运行时库的Binder接口是一致的。前面我们学习An droid硬件抽象层时,曾经在应用程序框架层中提供了一个硬 件访问服务HelloService,这个Service运行在一个独立的进程中充当Server的角色,使用这个Service的Client运行在另一个进程中,它们之间就是通过Binder机制来通信的了。这里,我们就使用HelloService这个例子来分析An droid系统进程间通信Binder机制在应用程序框架层的Java接口

4、源代码。所以希望读者在阅读下 面的内容之前,先了解一下前面 在Ubu ntu上为An droid系统的Applicatio n Frameworks层增加硬件访问服务这篇文章。这篇文章通过五个情景来学习An droid系统进程间通信Bin der机制在应用程序框架层的Java接口: 1.获取Service Manager的Java远程接口的过程;2. HelloService 接口的定义;3. HelloService 的启动过程;4. Client 获取 HelloService 的Java远程接口的过程;5. Client通过HelloService的Java远程接口来使用 HelloSe

5、rvice提供的服务的过程。获取 Service Manager 的 Java 远程接口我们要获取的Service Manager的Java远程接口是一个ServiceManagerProxy 对象的IServiceManager接口。我们现在就来看看ServiceMan agerProxy 类是长什么样子的:卩施細“ Datef3ervicef-/l0nagcrPruxy Hiiider+asBmcer) iBinder+cmer/Lccallnteffacedescriator: String); Interface+tranact(: int, data: Parcel, reply;

6、Parcel,flajs int) booknriTiScrYKcM-diiagr+gdSer-.Fite( riame : arrng ): 1 Binder +a(WServioe( name: String, service: ISrider):7这里可以看出,ServiceManagerProxy 类实现了 IServiceManager 接口, IServiceManager提供了 getService禾口 addService两个成员函数来管理系统中的 Service。从ServiceManagerProxy 类的构造函数可以看出,它需要一个BinderProxy 对象的IBind

7、er接口来作为参数。因此,要获取 Service Manager的Java远程接口 ServiceManagerProxy,首先要有一个 BinderProxy对象。下面将会看到这个 BinderProxy对象是如何获得的。再来看一下是通过什么路径来获取Service Manager的Java远程接口ServiceManagerProxy 的。这个主角就是 ServiceManager 了,我们也先看一下 ServiceManager是长什么样子的:11ServiceMlan ager1 sServiceManager: IServiceManagerService Many erKative

8、: 宀.+getlSeiiceMa nager(): IServiceManager +getService-i name : Strng ): IBinder +addSerice( naine: String, serHce : IBinder)J+Bslrtrfacfl( obj.IBinder): tServiceldsriagerpackage Data ServrceManagerNnterface+asBinder-). IBmderJISeruiceMfina ger.+getSefvbce( name: String): filndef +addService( name:

9、String, service : IBinder)ServiceManager类有一个静态成员函数 getlServiceManager,它的作用就 是用来获取Service Manager的Java远程接口了,而这个函数又是通过ServiceManagerNative 来获取 Service Manager 的 Java 远程接口的。接下来,我们就看一下 ServiceMa nager.getlServiceMa nager这个函数的实现,这个函数定义在 frameworks/base/core/java/a ndroid/os/ServiceMa nager.java 文件中:view

10、plain1.2.3.4.5.6.7.8.public finalprivateprivateclass ServiceManager static IServiceManager sServiceManager;static IServiceManager getIServiceManager() if (sServiceManager != null ) return sServiceManager;9.9.10./ Find the service manager9.11. sServiceManager = ServiceManagerNative.aslnterface(Binder

11、lnternal.ge tContextObject();12. return sServiceManager;13. 1415. 如果其静态成员变量sServiceMa nager尚未创建,那么就调用ServiceMa nagerNative.as In terface函数来创建。在调用ServiceMa nagerNative.as In terface函数之前,首先要通过BinderInternal.getContextObject函数来获得一个 BinderProxy 对象。我们来看一下Binderlnternal.getContextObject的实现,这个函数定义在framewor

12、ks/base/core/java/com/a ndroid/i ntern al/os/B in derI ntern al.java文件中:view plain1. public class BinderInternal 23./*4. * Return the global context object of the system. This is usually5. * an implementation of IServiceManager, which you can use to find6. * other services.7. */8. public static fina

13、l native IBinder getContextObject();9.1011. 这里可以看出,Binderlnternal.getContextObject是一个JNI方法,它实现在frameworks/base/core/j ni/a ndroid_util_Bi nder.cpp文件中:view plain1. static jobject android_os_Binderlnternal_getContextObject(JNIEnv* env, jobje ct clazz)2. 3. sp b = ProcessState:self()-getContextObject(N

14、ULL);4. return javaObjectForIBinder(env, b);5. 这里看到我们熟悉的ProcessState:self()-getContextObject 函数,具体可以 参考浅谈An droid系统进程间通信(IPC)机制Bin der中的Server和Clie nt获得Service Manager 接口之路一文。ProcessState:self()-getContextObject函数返回一个BpBinder对象,它的句柄值是0,即下面语句:view plain1. sp b = ProcessState:self()-getContextObject(N

15、ULL);相当于是:view plain1. sp b = new BpBinder(0);接着调用javaObjectForIBinder把这个BpBinder对象转换成一个BinderProxy 对象:view plain1. jobject javaObjectForlBinder(JNIEnv* env,const sp& val)2. 3. if (val = NULL) return NULL;4.4. if (val-checkSubclass(&gBinderOffsets) 5. / One of our own!6. jobject object =static_cast

16、(val.get()-object();7. printf(objectForBinder %p: its our own %p!n, val.get(), object);8. return object;9. 11.12. / For the rest of the function we will hold this lock, to serialize13. / looking/creation of Java proxies for native Binder proxies.14. AutoMutex(mProxyLock);15.15. / Someone elses. do w

17、e know about it?16. jobject object = (jobject)val-findObject (&gBinderProxyOffsets);17. if (object != NULL) 18. jobject res = env-CallObjectMethod(object, gWeakReferenceOffsets.mGet);19. if (res != NULL) 20. LOGV(objectForBinder %p: found existing %p!n, val.get(), res)J21. return res;22. 23. LOGV( P

18、roxy object %p of IBinder %p no longer in working set!, object, val.get();24. android_atomic_dec(&gNumProxyRefs);26.val-detachObject(&gBinderProxyOffsets);27.env-DeleteGlobalRef(object);28.29.30.object = env-NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);31.if (object != NUL

19、L) 32.LOGV(objectForBinder %p: created new %p!n, val.get(), object);33./ The proxy holds a reference to the native object.34.env-SetlntField(object, gBinderProxyOffsets.mObject,(int )val.get()35.val-incStrong(object);36.37./ The native object needs to hold a weak reference back to the38./ proxy, so

20、we can retrieve the same proxy if it is still active.39.jobject refObject = env-NewGlobalRef(40.env-GetObjectField(object, gBinderProxyOffsets.mSelf);41.val-attachObject(&gBinderProxyOffsets, refObject,42.jnienv_to_javavm(env), proxy_cleanup);43.44./ Note that a new object reference has been created

21、.45.android_atomic_inc (&gNumProxyRefs);46.incRefsCreated(env);47.48.49.return object;50.在介绍这个函数之前,先来看两个变量gBinderOffsets和gBi nderProxyOffsets的定义。先看 gBinderOffsets 的定义:view plain1. static struct bindernative_offsets_t2. 3. / Class state.4. jclass mClass;5. jmethodID mExecTransact;6.6. / Object state.

22、7. jfieldID mObject;9.10. gBinderOffsets;Binder类的os_Bin der);简单来说,gBinderOffsets变量是用来记录上面第二个类图中的相关信息的,它是在注册Binder类的JNI方法的int_register_android,函数初始化的:view plain1. const char * const kBinderPathName = android/os/Binder ;2.2. static int int_register_android_os_Binder(JNIEnv* env)3. 4. jclass clazz;6.5.

23、 clazz = env-FindClass(kBinderPathName);6. LOG_FATAL_IF(clazz = NULL,Unable to find class android.os.Binder9.7. gBinderOffsets.mClass = (jclass) env-NewGlobalRef(clazz);8. gBinderOffsets.mExecTransact9. = env-GetMethodlD(clazz,execTransact , (IIII)Z );10. assert(gBinderOffsets.mExecTransact);14.11.

24、gBinderOffsets.mObject12. = env-GetFieldID(clazz,mObject , I);13. assert(gBinderOffsets.mObject);18.14. return AndroidRuntime:registerNativeMethods(15. env, kBinderPathName,16. gBinderMethods, NELEM(gBinderMethods);17. 再来看 gBinderProxyOffsets 的定义:view plain1. static struct binderproxy_offsets_t2. 3.

25、 / Class state.4. jclass mClass;5. jmethodID mConstructor;6. jmethodID mSendDeathNotice;7.7. /Object state.8. jfieldID mObject;9. jfieldID mSelf;11.12. gBinderProxyOffsets;简单来说,gBin derProxyOffsets是用来变量是用来记录上面第一个图中的BinderProxy类的相关信息的,它是在注册BinderProxy类的JNI方法的in t_register_a ndroid_os_B in derProxy函数初

26、始化的:view plain1. const char * const kBinderProxyPathName = android/os/BinderProxy;2.2. static int int_register_android_os_BinderProxy(JNIEnv* env)3. 4. jclass clazz;6.5. clazz = env-FindClass(java/lang/ref/WeakReference);6. LOG_FATAL_IF(clazz = NULL,Unable to find class java.lang.ref.WeakReference);

27、7. gWeakReferenceOffsets.mClass = (jclass) env-NewGlobalRef(clazz);8. gWeakReferenceOffsets.mGet9. = env-GetMethodlD(clazz,get , ()Ljava/lang/Object;);10. assert(gWeakReferenceOffsets.mGet);13.11. clazz = env-FindClass(java/lang/Error );12. LOG_FATAL_IF(clazz = NULL,Unable to find class java.lang.Er

28、ror);13. gErrorOffsets.mClass = (jclass) env-NewGlobalRef(clazz);17.14. clazz = env-FindClass(kBinderProxyPathName);15. LOG_FATAL_IF(clazz = NULL,Unable to find class android.os.BinderProxy);20.16. gBinderProxyOffsets.mClass = (jclass) env-NewGlobalRef(clazz);17. gBinderProxyOffsets.mConstructor18.

29、= env-GetMethodID(claz z, , ()V);19. assert(gBinderProxyOffsets.mConstructor);20. gBinderProxyOffsets.mSendDeathNotice21. = env-GetStaticMethodlD(clazz,sendDeathNotice , (Landroid/os/IBinder$DeathRecipient;)V );22. assert(gBinderProxyOffsets.mSendDeathNotice);28.23. gBinderProxyOffsets.mObject24. =

30、env-GetFieldID(clazz,mObject , I);25. assert(gBinderProxyOffsets.mObject);26. gBinderProxyOffsets.mSelf27. = env-GetFieldlD(clazz,mSelf , Ljava/lang/ref/WeakReference;);28. assert(gBinderProxyOffsets.mSelf);35.29. return AndroidRuntime:registerNativeMethods(30. env, kBinderProxyPathName,31. gBinderP

31、roxyMethods, NELEM(gBinderProxyMethods);32. 回到前面的javaObjectForlBinder函数中,下面这段代码:view plain1. if (val-checkSubclass(&gBinderOffsets) 2. / One of our own!3. jobject object =static_cast (val.get()-object();4. /printf(objectForBinder %p: its our own %p!n, val.get(), object);5. return object;6. 前面说过,这里传进

32、来的参数是一个BpBinder的指针,而BpBinder:checkSubclass 继承于父类 IBinder:checkSubclass ,它什么也不做就返 回 false。于是函数继续往下执行:view plain1. jobject object = (jobject)val-findObject (&gBinderProxyOffsets);由于这个BpBinder对象是第一创建,它里面什么对象也没有,因此,这里返 回的 object 为 NULL。于是函数又继续往下执行:view plain1. object = env-NewObject(gBinderProxyOffsets.

33、mClass, gBinderProxyOffsets.mConstructor);这里,就创建了一个 BinderProxy对象了。创建了之后,要把这个 BpBinder 对象和这个BinderProxy对象关联起来:view plain1. env-SetlntField(object, gBinderProxyOffsets.mObject, (int )val.get();就是通过 BinderProxy.mObject 成员变量来关联的了,BinderProxy.mObject成员变量记录了这个BpBinder对象的地址。接下去,还要把它放到BpBinder里面去,下次就要使用时,就

34、可以在上一步 调用BpBinder:findObj把它找回来了:view plain1. val-attachObject(&gBinderProxyOffsets, refObject,2. jnienv_to_javavm(env), proxy_cleanup);最后,就把这个BinderProxy返回到an droid_os_Bi nderl nternal_getCo ntextObject函数,最终返回到最开始的ServiceMa nager.getlServiceMa nager 函数中来了,于是,我们就获得一个 BinderProxy 对象了。回到 ServiceManager

35、.getlServiceManager中,从下面语句返回:view plain1. sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject();相当于是:view plain1. sServiceManager = ServiceManagerNative.asInterface(new BinderProxy();接下去就是调用ServiceMa nagerNative.as In terface函数了,这个函数定义在frameworks/base/core/java/a ndroi

36、d/os/ServiceMa nagerNative.java文件中:view plain1. public abstract class ServiceManagerNative2.3.4.staticpublicIServiceManager asInterface(IBinder obj)5.6.if (obj =null ) 7.returnnull ;8.9.IServiceManager in =10.(IServiceManager)obj.queryLocallnteface(descriptor);11.if (in !=null ) 12.return in;13.14.1

37、5.return new ServiceManagerProxy(obj);16.17.18.这里的参数obj是一个BinderProxy对象,它的queryLocallnterface 函数返 回null。因此,最终以这个 BinderProxy对象为参数创建一个 ServiceManagerProxy 对象。返回到 ServiceManager.getlServiceManager 中,从下面语句返回:view plain1. sServiceManager = ServiceManagerNative.aslnteface(new BinderProxy();就相当于是:view pla

38、in1. sServiceManager = new ServiceManagerProxy( new BinderProxy();于是,我们的目标终于完成了。总结一下,就是在Java层,我们拥有了一个 Service Manager远程接口 ServiceManagerProxy,而这个 ServiceManagerProxy 对象在 JNI 层有一个句柄值 为0的BpBinder对象与之通过 gBinderProxyOffsets 关联起来。这样获取Service Manager的Java远程接口的过程就完成了。二. HelloService 接口的定义前面我们在学习An droid系统的

39、硬件抽象层(HAL )时,在在Ubun tu上为 An droid系统的Applicati on Frameworks 层增加硬件访问服务这篇文章中,我们编 写了一个硬件服务HelloService,它的服务接口定义在 frameworks/base/core/java/a ndroid/os/IHelloService.aidl文件中:view plain1.package android.os;2.3.interfaceIHelloService4.5.voidsetVal( int val);6.intgetVal();7.这个服务接口很简单,只有两个函数,分别用来读写硬件寄存器。注意,

40、这是一个aidl文件,编译后会生成一个IHelloService.java。我们来看 一下这个文件的内容隐藏着什么奥秘,可以这么神奇地支持进程间通信。view plain1./*2.* This file is auto-generated. DO NOT MODIFY.3.* Original file: frameworks/base/core/java/android/os/IHelloService.aidl4.*/5.packageandroid.os;6.publicinterfaceIHelloServiceextends android.osl nterface7.8./* L

41、ocal-side IPC implementation stub class. */9.public staticabstractclass Stub extends android.os.Binderimplements android.os .IH elloService10.11.private static final java.lang.String DESCRIPTOR =android.os.IHelloService12./* Construct the stub at attach it to the interface. */13.public Stub()14.15.t

42、his .attachInterface(this , DESCRIPTOR);16.17.18./*19.* Cast an IBinder object into an android.osH elloService interface,20.* generating a proxy if needed.21.*/22.public staticandroid.os .IH elloService asInterface(android.os.IBinder obj)23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.43

43、.44.45.46.47.48.49.50.51.52.53.54.55.56.57.58.59.60.61.62.63.if (obj= null ) return null ;android.os.IInterface iin = (android.os.llnterface)obj.queryLoca llnterface(DESCRIPTOR);if (iin!= null )&(iin instanceof android.os.IHelloService) return (android.os.IHelloService)iin);returnnew android.osH ell

44、oService.Stub.Proxy(obj);public android.osBinder asBinder()return this ;Overridepublic boolean onTransact( int code, android.os.Parcel data, android.os.Parcel reply,int flags) throws android.os.RemoteExceptionswitch (code)case INTERFACE_TRANSACTION:reply.writeString(DESCRIPTOR);return true ;case TRA

45、NSACTION_setVal:data.enforceInterface(DESCRIPTOR);int _arg0;_arg0 = data.readInt();this .setVal(_argO);reply.writeNoException();return true ;case TRANSACTION_getVal:data.enforceInterface(DESCRIPTOR);int _result = this .getVal();reply.writeNoException();reply.writeInt( result);64.return true ;65.66.6

46、7.68.69.70.71.72.73.74.75.76.77.78.79.80.81.82.83.84.85.86.87.88.89.90.91.92.93.94.95.96.97.98.99.100.101.102.103.104.105.106.107.return super .onTransact(code, data, reply, flags);private static class Proxy implementsandroid.os .IH elloServiceprivate android.osBinder mRemote;Proxy(android.osBinder

47、remote)mRemote = remote;public android.os .I Binder asBinder()return mRemote;public java .l ang.String getlnterfaceDescriptor()return DESCRIPTOR;public void setVal( int val) throws android.os.RemoteException android.os.Parcel _data = android.os.Parcel.obtain();android.os.Parcel _reply = android.os.P

48、arcel.obtain();try _data.writelnterfaceToken(DESCRIPTOR);_data.writelnt(val);mRemote.transact(Stub.TRANSACTION_setVal, _data, _reply,0);_reply.readException();finally _reply.recycle();_data.recycle();public int getVal() throws android.os.RemoteExceptionandroid.os.Parcel _data = android.os.Parcel.obt

49、ain();108.android.os.Parcel _reply = android.os.Parcel.obtain();109.int _result;110.try 111._data.writelnterfaceToken(DESCRIPTOR);112.mRemote.transact(Stub.TRANSACTION_getVal, _data, _reply,0);113._reply.readException();114._result = _reply.readInt();115.116.finally117._reply.recycle();118._data.rec

50、ycle();119.120.return _result;121.122.123.124.static final int TRANSACTION_setVal = (android.osBinder.FIRST_CALL_TRANSACTION + 0);125.static final int TRANSACTION_getVal = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);126.127.128.public void setVal( int val) throws android.os.RemoteException;129.p

51、ublic int getVal()throws android.os.RemoteException;130.这里我们可以看到IHelloService.aidl这个文件编译后的真面目,原来就是根 据IHelloService接口的定义生成相应的 Stub和Proxy类,这个就是我们熟悉的 Binder机制的内容了,即实现这个 HelloService的Server必须继续于这里的 IHelloService.Stub类,而这个HelloService的远程接口就是这里的 IHelloService.Stub.Proxy 对象获得的IHelloService接口。接下来的内容,我们就 可以看

52、到IHelloService.Stub禾口 IHelloService.Stub.Proxy是怎么创建或者使用的。三. HelloService的启动过程在讨论HelloService的启动过程之前,我们先来看一下实现HelloService接口的Server是怎么定义的。回忆在Ubun tu上为An droid系统的Application Frameworks 层增加硬件访 问服务一文,我们在 frameworks/base/services/java/com/android/server目录下新增了一个 HelloService.java 文件:view plain1.package co

53、m.android.server;2.3.import android.content.Context;4.import android.os .IH elloService;5.import android.util.Slog;6.7.public class HelloServiceextendsIHelloService.Stub 8.privatestaticfinal String TAG=HelloService;9.10.HelloService() 11.init_native();12.13.14.public void setVal( int val) 15.setVal_

54、native(val);16.17.18.public int getVal() 19.return getVal_native();20.21.22.privatestaticnative booleaninit_native();23.private staticnative voidsetVal_native(int val);24.privatestaticnative int getVal_native();25.这里,我们可以看到,HelloService继续了 IHelloService.Stub类,它通过本 地方法调用实现了 getVal和setVal两个函数。我们不关心这两个

55、函数的具体实现, 有兴趣的读者可以参考 在Ubu ntu上为An droid系统的Application Frameworks 层 增加硬件访问服务一文。有了 HelloService这个Server类后,下一步就是考虑怎么样把它启动起来了。在 frameworks/base/services/java/com/android/server/SystemServer.java 文件中, 定义了 SystemServer类。SystemServer对象是在系统启动的时候创建的,它被创 建的时候会启动一个线程来创建HelloService,并且把它添加到 Service Manager守护进程中去

56、,最后进入一个循环,等待Client的请求。我们来看一下这部份的代码:view plain1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20.21.22.23.24.25.26.27.28.29.30.31.32.33.34.35.36.37.38.39.40.41.42.class ServerThread extends Thread Overridepublic void run() Looper.prepare();try Slog.i(TAG,Hello Service );ServiceManager.addService(hell

57、o , new HelloService();catch (Throwable e) Slog.e(TAG,Failure starting Hello Service, e);Looper.loop();public class SystemServer* This method is called from Zygote to initialize the system. This will cause the native* services (SurfaceFlinger, AudioFlinger, etc.) to be started. After th at it will c

58、all back* up into init2() to start the Android services.*/native public static void init1(String args);43.public staticfinal void init2() 44.Slog.i(TAG,Entered the Android system server!);45.Thread thr =new ServerThread();46.thr.setName(android.server.ServerThread);47.thr.start();48.49.50.这里,我们可以看到,在 ServerThread.ru n函数中,执行了下面代码把HelloService 添加到Service Manager中去,并且通过 Looper.loop进入循环等待 Client的请求。这里我们关注把 HelloService添加到Service Manager中去的代码:view plain1.try/ 2.Slog.i(TAG,Hello Service);3.Ser

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!