![Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡要介紹_第1頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/26/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a1.gif)
![Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡要介紹_第2頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/26/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a2.gif)
![Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡要介紹_第3頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/26/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a3.gif)
![Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡要介紹_第4頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/26/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a4.gif)
![Android系統(tǒng)匿名共享內(nèi)存Ashmem(Anonymous Shared Memory)簡要介紹_第5頁](http://file3.renrendoc.com/fileroot_temp3/2022-1/26/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a/f36e724e-90df-4d5c-8f87-fd78bb9e0e2a5.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、 在Android系統(tǒng)中,提供了獨特的匿名共享內(nèi)存子系統(tǒng)Ashmem(Anonymous Shared Memory),它以驅(qū)動程序的形式實現(xiàn)在內(nèi)核空間中。它有兩個特點,一是能夠輔助內(nèi)存管理系統(tǒng)來有效地管理不再使用的內(nèi)存塊,二是它通過Binder進程間通信機制來實現(xiàn)進程間的內(nèi)存共享。本文中,我們將通過實例來簡要介紹Android系統(tǒng)的匿名共享內(nèi)存的使用方法,使得我們對Android系統(tǒng)的匿名共享內(nèi)存機制有一個感性的認識,為進一步學(xué)習(xí)它的源代碼實現(xiàn)打下基礎(chǔ)。 Android系統(tǒng)的匿
2、名共享內(nèi)存子系統(tǒng)的主體是以驅(qū)動程序的形式實現(xiàn)在內(nèi)核空間的,同時,在系統(tǒng)運行時庫層和應(yīng)用程序框架層提供了訪問接口,其中,在系統(tǒng)運行時庫層提供了C/C+調(diào)用接口,而在應(yīng)用程序框架層提供了Java調(diào)用接口。這里,我們將直接通過應(yīng)用程序框架層提供的Java調(diào)用接口來說明匿名共享內(nèi)存子系統(tǒng)Ashmem的使用方法,畢竟我們在Android開發(fā)應(yīng)用程序時,是基于Java語言的,而實際上,應(yīng)用程序框架層的Java調(diào)用接口是通過JNI方法來調(diào)用系統(tǒng)運行時庫層的C/C+調(diào)用接口,最后進入到內(nèi)核空間的Ashmem驅(qū)動程序去的。 我們在這里舉的例子是一個
3、名為Ashmem的應(yīng)用程序,它包含了一個Server端和一個Client端實現(xiàn),其中,Server端是以Service的形式實現(xiàn)的,在這里Service里面,創(chuàng)建一個匿名共享內(nèi)存文件,而Client是一個Activity,這個Activity通過Binder進程間通信機制獲得前面這個Service創(chuàng)建的匿名共享內(nèi)存文件的句柄,從而實現(xiàn)共享。在Android應(yīng)用程序框架層,提供了一個MemoryFile接口來封裝了匿名共享內(nèi)存文件的創(chuàng)建和使用,它實現(xiàn)在frameworks/base/core/java/android/os/MemoryFile.java文件中。下面,我們就來看看Server端是
4、如何通過MemoryFile類來創(chuàng)建匿名共享內(nèi)存文件的以及Client是如何獲得這個匿名共享內(nèi)存文件的句柄的。 在MemoryFile類中,提供了兩種創(chuàng)建匿名共享內(nèi)存的方法,我們通過MemoryFile類的構(gòu)造函數(shù)來看看這兩種使用方法:view plain1. public class MemoryFile 2. 3. . 4. 5. &
5、#160;/* 6. * Allocates a new ashmem region. The region is initially not purgable. 7. * 8. * param name optional name for the
6、0;file (can be null). 9. * param length of the memory file in bytes. 10. * throws IOException if the memory file could not be created.
7、60;11. */ 12. public MemoryFile(String name, int length) throws IOException 13. mLength = length; 14.
8、; mFD = native_open(name, length); 15. mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE); 16. mOwnsRegio
9、n = true; 17. 18. 19. /* 20. * Creates a reference to an existing memory file. Changes to the original file
10、21. * will be available through this reference. 22. * Calls to link #allowPurging(boolean) on the returned MemoryFile will fail. 23. *
11、0;24. * param fd File descriptor for an existing memory file, as returned by 25. * link #getFileDescriptor(). This file
12、descriptor will be closed 26. * by link #close(). 27. * param length Length of the memory file in bytes. 28.
13、; * param mode File mode. Currently only "r" for read-only access is supported. 29. * throws NullPointerException if <code>fd</code> is null. 3
14、0. * throws IOException If <code>fd</code> does not refer to an existing memory file, 31. * or if the file&
15、#160;mode of the existing memory file is more restrictive 32. * than <code>mode</code>. 33. * 34. *
16、0;hide 35. */ 36. public MemoryFile(FileDescriptor fd, int length, String mode) throws IOException 37. if (fd = null
17、) 38. throw new NullPointerException("File descriptor is null."); 39. 40. &
18、#160; if (!isMemoryFile(fd) 41. throw new IllegalArgumentException("Not a memory file."); 42. &
19、#160;43. mLength = length; 44. mFD = fd; 45. mAddress = native_mmap(mFD, length, modeToProt(mo
20、de); 46. mOwnsRegion = false; 47. 48. 49. . 50. 從注釋中,我們可以看出這兩個構(gòu)造函數(shù)的使用方法,這里就不再詳述了。兩個構(gòu)造函數(shù)的主要區(qū)別
21、是第一個參數(shù),第一種構(gòu)造方法是以指定的字符串調(diào)用JNI方法native_open來創(chuàng)建一個匿名共享內(nèi)存文件,從而得到一個文件描述符,接著就以這個文件描述符為參數(shù)調(diào)用JNI方法natvie_mmap把這個匿名共享內(nèi)存文件映射在進程空間中,然后就可以通過這個映射后得到的地址空間來直接訪問內(nèi)存數(shù)據(jù)了;第二種構(gòu)造方法是以指定的文件描述符來直接調(diào)用JNI方法natvie_mmap把這個匿名共享內(nèi)存文件映射在進程空間中,然后進行訪問,而這個文件描述符就必須要是一個匿名共享內(nèi)存文件的文件描述符,這是通過一個內(nèi)部函數(shù)isMemoryFile來驗證的,而這個內(nèi)部函數(shù)isMemoryFile也是通過JNI方法調(diào)用
22、來進一步驗證的。前面所提到的這些JNI方法調(diào)用,最終都是通過系統(tǒng)運行時庫層進入到內(nèi)核空間的Ashmem驅(qū)動程序中去,不過這里我們不關(guān)心這些JNI方法、系統(tǒng)運行庫層調(diào)用以及Ashmem驅(qū)動程序的具體實現(xiàn),在接下來的兩篇文章中,我們將會著重介紹,這里我們只關(guān)注MemoryFile這個類的使用方法。 前面我們說到,我們在這里舉的例子包含了一個Server端和一個Client端實現(xiàn),其中, Server端就是通過前面一個構(gòu)造函數(shù)來創(chuàng)建一個匿名共享內(nèi)存文件,接著,Client端過Binder進程間通信機制來向Server請求這個匿名共享內(nèi)存
23、的文件描述符,有了這個文件描述符之后,就可以通過后面一個構(gòu)造函數(shù)來共享這個內(nèi)存文件了。 因為涉及到Binder進程間通信,我們首先定義好Binder進程間通信接口。Binder進程間通信機制的相關(guān)介紹,請參考前面一篇文章Android進程間通信(IPC)機制Binder簡要介紹和學(xué)習(xí)計劃,這里就不詳細介紹了,直接進入主題。 首先在源代碼工程的packages/experimental目錄下創(chuàng)建一個應(yīng)用程序工程目錄Ashmem。關(guān)于如何獲得Android源代碼工程,請參
24、考在Ubuntu上下載、編譯和安裝Android最新源代碼一文;關(guān)于如何在Android源代碼工程中創(chuàng)建應(yīng)用程序工程,請參考在Ubuntu上為Android系統(tǒng)內(nèi)置Java應(yīng)用程序測試Application Frameworks層的硬件服務(wù) 這里要用到的Binder進程間通信接口定義在src/shy/luo/ashmem/IMemoryService.java文件中:view plain1. package2. 3. import4. import5. import6. import7. import8.
25、import9. import10. 11. public interface IMemoryService extends IInterface 12. public static abstract class Stub extends Binder implements IMemoryService 13. &
26、#160; private static final String DESCRIPTOR = 14. 15. public Stub() 16. at
27、tachInterface(this, DESCRIPTOR); 17. 18. 19. public static IMemoryService asInterface(IBinder obj) 20.
28、 if (obj = null) 21. return null; 22.
29、; 23. 24. IInterface iin = (IInterface)obj.queryLocalInterface(DESCRIPTOR); 25. if (iin != n
30、ull && iin instanceof IMemoryService) 26. return (IMemoryService)iin; 27.
31、60; 28. 29. return new30. 31. 32. public IBinder asBinder()
32、; 33. return this; 34. 35. 36. Override 37.
33、160; public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws38. switch (code) 39.
34、160; case INTERFACE_TRANSACTION: 40. reply.writeString(DESCRIPTOR); 41.
35、0; return true; 42. 43. case TRANSACTION_getFileDescriptor: 44. &
36、#160; data.enforceInterface(DESCRIPTOR); 45. 46. &
37、#160; ParcelFileDescriptor result = this.getFileDescriptor(); 47. 48. &
38、#160; reply.writeNoException(); 49. 50. if (result&
39、#160;!= null) 51. reply.writeInt(1); 52.
40、0; result.writeToParcel(reply, 0); 53. else 54.
41、0; reply.writeInt(0); 55. 56. 57. return true;
42、;58. 59. case TRANSACTION_setValue: 60.
43、0; data.enforceInterface(DESCRIPTOR); 61. 62. int val = dat
44、a.readInt(); 63. setValue(val); 64. 65.
45、0; reply.writeNoException(); 66. 67. &
46、#160; return true; 68. 69. 70. 71.
47、0; return super.onTransact(code, data, reply, flags); 72. 73. 74. private static class Proxy implements IMemoryService&
48、#160; 75. private IBinder mRemote; 76. 77. Proxy(IBinder remote) 78.
49、60; mRemote = remote; 79. 80. 81. public
50、 IBinder asBinder() 82. return mRemote; 83. 84. 85. &
51、#160; public String getInterfaceDescriptor() 86. return DESCRIPTOR; 87.
52、 88. 89. public ParcelFileDescriptor getFileDescriptor() throws RemoteException 90.
53、 Parcel data = Parcel.obtain(); 91. Parcel reply = Parcel.obtain(); 92. 93.
54、; ParcelFileDescriptor result; 94. 95. try 96.
55、; data.writeInterfaceToken(DESCRIPTOR); 97. 98. mR
56、emote.transact(Stub.TRANSACTION_getFileDescriptor, data, reply, 0); 99. 100. reply.readExcepti
57、on(); 101. if (0 != reply.readInt() 102.103.
58、160; else 104. result = null; 105.
59、 106. finally 107. &
60、#160; reply.recycle(); 108. data.recycle(); 109.
61、160; 110. 111. return result; 112. 113.
62、; 114. public void setValue(int val) throws RemoteException 115. Parcel data
63、0;= Parcel.obtain(); 116. Parcel reply = Parcel.obtain(); 117. 118.
64、0; try 119. data.writeInterfaceToken(DESCRIPTOR); 120.
65、160; data.writeInt(val); 121. 122. mRemote.transact(Stub.TRANSACTION_setValue, data, reply, 0); 123. &
66、#160; 124. reply.readException(); 125.
67、; finally 126. reply.recycle(); 127.
68、160; data.recycle(); 128. 129. &
69、#160; 130. 131. 132. static final int TRANSACTION_getFileDescriptor = IBinder.FIRST_CALL_TRANSACTION + 0; 133.
70、 static final int TRANSACTION_setValue = IBinder.FIRST_CALL_TRANSACTION + 1; 134. 135. 136. 137. public ParcelFileDesc
71、riptor getFileDescriptor() throws RemoteException; 138. public void setValue(int val) throws RemoteException; 139. 這里主要是定義了IMemoryService接口,它里面有兩個調(diào)用接口:view plain1. publi
72、c ParcelFileDescriptor getFileDescriptor() throws RemoteException; 2. public void setValue(int val) throws RemoteException; Android系統(tǒng)進程間通信Binder機制在應(yīng)用程序框架層的Java接口源代碼分析一文。 有了Binder進程間通信接口之后,接下來就是要在Server
73、端實現(xiàn)一個本地服務(wù)了。這里,Server端實現(xiàn)的本地服務(wù)名為MemoryService,實現(xiàn)在src/shy/luo/ashmem/MemoryService.java文件中:view plain1. package2. 3. import4. import5. 6. import7. import8. import9. import10. 11. public class MemoryService extends IMemoryService.Stub
74、160;12. private final static String LOG_TAG = 13. private MemoryFile file = null; 14. 15. public MemoryService()
75、160; 16. try 17. file = new MemoryFile("Ashmem", 4
76、); 18. setValue(0); 19. 20
77、. catch(IOException ex) 21. Log.i(LOG_
78、TAG, "Failed to create memory file."); 22. ex.printStackTrace(); 23.
79、 24. 25. 26. public ParcelFileDescriptor getFileDescriptor() 27. Log.i(LOG_T
80、AG, "Get File Descriptor."); 28. 29. ParcelFileDescriptor pfd = null; 30. 31. try 32.
81、60; pfd = file.getParcelFileDescriptor(); 33. catch(IOException ex) 34. Log.i(
82、LOG_TAG, "Failed to get file descriptor."); 35. ex.printStackTrace(); 36. 37. 38.
83、; return pfd; 39. 40. 41. public void setValue(int val) 42. if(file =
84、;null) 43. return; 44. 45. 46. byte buffer = new byte4;
85、; 47. buffer0 = (byte)(val >>> 24) & 0xFF); 48. buffer1 = (byte)(val >>> 16) & 0xFF)
86、; 49. buffer2 = (byte)(val >>> 8) & 0xFF); 50. buffer3 = (byte)(val & 0xFF); 51.
87、; 52. try 53. file.writeBytes(buffer, 0, 0, 4); 54.
88、160; Log.i(LOG_TAG, "Set value " + val + " to memory file. "); 55. 56. catch(IOExce
89、ption ex) 57. Log.i(LOG_TAG, "Failed to write bytes to memory file."); 58. ex.
90、printStackTrace(); 59. 60. 61. 注意,這里的MemoryService類實現(xiàn)了IMemoryService.Stub類,表示這是一個Binder服務(wù)的本地實現(xiàn)。在構(gòu)造函數(shù)中,通過指定文件名和文件大小來創(chuàng)建了一個匿名共享內(nèi)存文件,即創(chuàng)建MemoryFile的一個實例,
91、并保存在類成員變量file中。這個匿名共享內(nèi)存文件名為"Ashmem",大小為4個節(jié)字,剛好容納一個整數(shù),我們這里舉的例子就是要說明如果創(chuàng)建一個匿名共享內(nèi)存來在兩個進程間實現(xiàn)共享一個整數(shù)了。當(dāng)然,在實際應(yīng)用中,可以根據(jù)需要創(chuàng)建合適大小的共享內(nèi)存來共享有意義的數(shù)據(jù)。 這里還實現(xiàn)了IMemoryService.Stub的兩個接口getFileDescriptor和setVal,一個用來獲取匿名共享內(nèi)存文件的文件描述符,一個來往匿名共享內(nèi)存文件中寫入一個整數(shù),其中,接口getFileDescriptor的返回值是一個
92、ParcelFileDescriptor。在Java中,是用FileDescriptor類來表示一個文件描述符的,而ParcelFileDescriptor是用來序列化FileDescriptor的,以便在進程間調(diào)用時傳輸。 定義好本地服務(wù)好,就要定義一個Server來啟動這個服務(wù)了。這里定義的Server實現(xiàn)在src/shy/luo/ashmem/Server.java文件中:view plain1. package2. 3. import4. import5. import6. import7. imp
93、ort8. 9. public class Server extends Service 10. private final static String LOG_TAG = 11. 12. private MemoryService memoryService =
94、160;null; 13. 14. Override 15. public IBinder onBind(Intent intent) 16. return null; 17.
95、60;18. 19. Override 20. public void onCreate() 21. Log.i(LOG_TAG, "Create Memory Service."); 22. 23. memor
96、yService = new MemoryService(); 24. 25. try 26. ServiceManager.addService("AnonymousSharedMemory", memoryServi
97、ce); 27. Log.i(LOG_TAG, "Succeed to add memory service."); 28. catch (RuntimeException ex)
98、;29. Log.i(LOG_TAG, "Failed to add Memory Service."); 30. ex.printStackTrace(); 31.
99、60; 32. 33. 34. 35. Override 36. public void onStart(Intent intent, int startId) 37. &
100、#160; Log.i(LOG_TAG, "Start Memory Service."); 38. 39. 40. Override 41. public void onDestroy() 42. &
101、#160; Log.i(LOG_TAG, "Destroy Memory Service."); 43. 44. 這個Server繼承了Android系統(tǒng)應(yīng)用程序框架層提供的Service類,當(dāng)它被啟動時,運行在一個獨立的進程中。當(dāng)這個Server被啟動時,它的onCreate函數(shù)就會被調(diào)用,然后它就通過ServiceManage
102、r的addService接口來添加MemoryService了:view plain1. memoryService = new MemoryService(); 2. 3. try 4. ServiceManager.addService("AnonymousSharedMemory", memoryService); 5. Log.i(
103、LOG_TAG, "Succeed to add memory service."); 6. catch (RuntimeException ex) 7. Log.i(LOG_TAG, "Failed to add Memory Service."); 8.
104、60;ex.printStackTrace(); 9. 這樣,當(dāng)這個Server成功啟動了,Client就可以通過ServiceManager的getService接口來獲取這個MemoryService了。 接著,我們就來看Client端的實現(xiàn)。Client端是一個Activity,實現(xiàn)在src/shy/luo/ashmem/Client.java文件中:view plain1. package2. 3. import
105、4. import5. 6. import7. import8. import9. import10. import11. import12. import13. import14. import15. import16. import17. import18. import19. 20. public class Client extends Activity implements OnClickListener 21.
106、60; private final static String LOG_TAG = 22. 23. IMemoryService memoryService = null; 24. MemoryFile memoryFile = null;
107、160;25. 26. private EditText valueText = null; 27. private Button readButton = null; 28. private Button writeButton
108、;= null; 29. private Button clearButton = null; 30. 31. Override 32. public void&
109、#160;onCreate(Bundle savedInstanceState) 33. super.onCreate(savedInstanceState); 34.35. 36. IMemoryService ms = getMemor
110、yService(); 37. if(ms = null) 38. startService(new Intent();
111、; 39. else 40. Log.i(LOG_TAG, "Memory Service has started."); 41.
112、60; 42. 43.44.45.46.47. 48. readButton.setOnClickListener(this); 49. writeButton.setOnClickListener(this); 50.
113、 clearButton.setOnClickListener(this); 51. 52. Log.i(LOG_TAG, "Client Activity
114、;Created."); 53. 54. 55. Override 56. public void onResume() 57. &
115、#160; super.onResume(); 58. 59. Log.i(LOG_TAG, "Client Activity Resumed."); 60. 61. 62.
116、0; Override 63. public void onPause() 64. super.onPause(); 65. 66.
117、; Log.i(LOG_TAG, "Client Activity Paused."); 67. 68. 69. Override 70.
118、0; public void onClick(View v) 71. if(v.equals(readButton) 72. int
119、 val = 0; 73. 74. MemoryFile mf = getMemoryFile(); 75. &
120、#160; if(mf != null) 76. try 77.
121、160; byte buffer = new byte4; 78. mf
122、.readBytes(buffer, 0, 0, 4); 79. 80.
123、60; val = (buffer0 << 24) | (buffer1 & 0xFF) << 16) | (buffer2 & 0xFF) << 8) | (buffer3 & 0xFF); 81.
124、; catch(IOException ex) 82. Log.i(LOG_TAG, "Failed to read bytes from
125、memory file."); 83. ex.printStackTrace(); 84.
126、 85. 86. 87.
127、 String text = String.valueOf(val); 88. valueText.setText(text); 89.
128、60;else if(v.equals(writeButton) 90. String text = valueText.getText().toString(); 91.
129、60; int val = Integer.parseInt(text); 92. 93. IMemoryService ms
130、60;= getMemoryService(); 94. if(ms != null) 95. try
131、160;96. ms.setValue(val); 97. catch(RemoteE
132、xception ex) 98. Log.i(LOG_TAG, "Failed to set value to memory service."); 99.
133、; ex.printStackTrace(); 100. 101.
134、0; 102. else if(v.equals(clearButton) 103. String
135、160;text = "" 104. valueText.setText(text); 105. 106.
136、 107. 108. private IMemoryService getMemoryService() 109. if(memoryService !=
137、 null) 110. return memoryService; 111. 112.
138、160; 113.114. ServiceManager.getService("AnonymousSharedMemory"); 115. 116.
139、 Log.i(LOG_TAG, memoryService != null ? "Succeed to get memeory service." : "Failed to get memory service."); 117.
140、160; 118. return memoryService; 119. 120. 121. priv
141、ate MemoryFile getMemoryFile() 122. if(memoryFile != null) 123. return memoryFile; 124. 125. 126.
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 繪畫心理治療課程-認識你自己課件
- 2021全球多行業(yè)重大網(wǎng)絡(luò)安全事件大盤點
- 安全員年度再教育3
- 2025-2030全球自動緊湊型視野計行業(yè)調(diào)研及趨勢分析報告
- 2025-2030全球商用蘑菇殺菌設(shè)備行業(yè)調(diào)研及趨勢分析報告
- 2025年全球及中國粘度過程分析儀行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025年全球及中國磨削數(shù)控系統(tǒng)行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 2025-2030全球水力冷凝鍋爐行業(yè)調(diào)研及趨勢分析報告
- 2025年全球及中國電動甲板機械行業(yè)頭部企業(yè)市場占有率及排名調(diào)研報告
- 照明亮化工程施工合同
- 《梅大高速茶陽路段“5·1”塌方災(zāi)害調(diào)查評估報告》專題警示學(xué)習(xí)
- 2024年09月北京中信銀行北京分行社會招考(917)筆試歷年參考題庫附帶答案詳解
- 《大健康解讀》課件
- 2025年度交通運輸規(guī)劃外聘專家咨詢協(xié)議3篇
- 2024年公司領(lǐng)導(dǎo)在新年動員會上的講話樣本(3篇)
- 2025年中國濕度傳感器行業(yè)深度分析、投資前景、趨勢預(yù)測報告(智研咨詢)
- 人教版道德與法治二年級下冊《第一單元 讓我試試看》大單元整體教學(xué)設(shè)計2022課標
- 聯(lián)合體三方協(xié)議合同模板
- 2024年3季度青島房地產(chǎn)市場季度簡報
- 蘇東坡詞十首
- 2023年天津市文化和旅游局直屬事業(yè)單位招聘考試真題及答案
評論
0/150
提交評論