Android中的Parcel机制

  1. if (binder != NULL) {

  2. IBinder *local = binder->localBinder();

  3. if (!local) {

  4. BpBinder *proxy = binder->remoteBinder();

  5. if (proxy == NULL) {

  6. LOGE(“null proxy”);

  7. }

  8. const int32_t handle = proxy ? proxy->handle() : 0;

  9. obj.type = BINDER_TYPE_HANDLE;

  10. obj.handle = handle;

  11. obj.cookie = NULL;

  12. } else {

  13. obj.type = BINDER_TYPE_BINDER;

  14. obj.binder = local->getWeakRefs();

  15. obj.cookie = local;

  16. }

  17. } else {

  18. obj.type = BINDER_TYPE_BINDER;

  19. obj.binder = NULL;

  20. obj.cookie = NULL;

  21. }

  22. return finish_flatten_binder(binder, obj, out);

  23. }

  24. status_t flatten_binder(const sp& proc,

  25. const wp& binder, Parcel* out)

  26. {

  27. flat_binder_object obj;

  28. obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;

  29. if (binder != NULL) {

  30. sp real = binder.promote();

  31. if (real != NULL) {

  32. IBinder *local = real->localBinder();

  33. if (!local) {

  34. BpBinder *proxy = real->remoteBinder();

  35. if (proxy == NULL) {

  36. LOGE(“null proxy”);

  37. }

  38. const int32_t handle = proxy ? proxy->handle() : 0;

  39. obj.type = BINDER_TYPE_WEAK_HANDLE;

  40. obj.handle = handle;

  41. obj.cookie = NULL;

  42. } else {

  43. obj.type = BINDER_TYPE_WEAK_BINDER;

  44. obj.binder = binder.get_refs();

  45. obj.cookie = binder.unsafe_get();

  46. }

  47. return finish_flatten_binder(real, obj, out);

  48. }

  49. // XXX How to deal?  In order to flatten the given binder,

  50. // we need to probe it for information, which requires a primary

  51. // reference…  but we don’t have one.

  52. //

  53. // The OpenBinder implementation uses a dynamic_cast<> here,

  54. // but we can’t do that with the different reference counting

  55. // implementation we are using.

  56. LOGE(“Unable to unflatten Binder weak reference!”);

  57. obj.type = BINDER_TYPE_BINDER;

  58. obj.binder = NULL;

  59. obj.cookie = NULL;

  60. return finish_flatten_binder(NULL, obj, out);

  61. } else {

  62. obj.type = BINDER_TYPE_BINDER;

  63. obj.binder = NULL;

  64. obj.cookie = NULL;

  65. return finish_flatten_binder(NULL, obj, out);

  66. }

  67. }

  68. inline static status_t finish_unflatten_binder(

  69. BpBinder* proxy, const flat_binder_object& flat, const Parcel& in)

  70. {

  71. return NO_ERROR;

  72. }

  73. status_t unflatten_binder(const sp& proc,

  74. const Parcel& in, sp* out)

  75. {

  76. const flat_binder_object* flat = in.readObject(false);

  77. if (flat) {

  78. switch (flat->type) {

  79. case BINDER_TYPE_BINDER:

  80. *out = static_cast<IBinder*>(flat->cookie);

  81. return finish_unflatten_binder(NULL, *flat, in);

  82. case BINDER_TYPE_HANDLE:

  83. *out = proc->getStrongProxyForHandle(flat->handle);

  84. return finish_unflatten_binder(

  85. static_cast<BpBinder*>(out->get()), *flat, in);

  86. }

  87. }

  88. return BAD_TYPE;

  89. }

  90. status_t unflatten_binder(const sp& proc,

  91. const Parcel& in, wp* out)

  92. {

  93. const flat_binder_object* flat = in.readObject(false);

  94. if (flat) {

  95. switch (flat->type) {

  96. case BINDER_TYPE_BINDER:

  97. *out = static_cast<IBinder*>(flat->cookie);

  98. return finish_unflatten_binder(NULL, *flat, in);

  99. case BINDER_TYPE_WEAK_BINDER:

  100. if (flat->binder != NULL) {

  101. out->set_object_and_refs(

  102. static_cast<IBinder*>(flat->cookie),

  103. static_castRefBase::weakref\_type\*(flat->binder));

  104. } else {

  105. *out = NULL;

  106. }

  107. return finish_unflatten_binder(NULL, *flat, in);

  108. case BINDER_TYPE_HANDLE:

  109. case BINDER_TYPE_WEAK_HANDLE:

  110. *out = proc->getWeakProxyForHandle(flat->handle);

  111. return finish_unflatten_binder(

  112. static_cast<BpBinder*>(out->unsafe_get()), *flat, in);

  113. }

  114. }

  115. return BAD_TYPE;

  116. }

  117. // ---------------------------------------------------------------------------

  118. Parcel::Parcel()

  119. {

  120. initState();

  121. }

  122. Parcel::~Parcel()

  123. {

  124. freeDataNoInit();

  125. }

  126. const uint8_t* Parcel::data() const

  127. {

  128. return mData;

  129. }

  130. size_t Parcel::dataSize() const

  131. {

  132. return (mDataSize > mDataPos ? mDataSize : mDataPos);

  133. }

  134. size_t Parcel::dataAvail() const

  135. {

  136. // TODO: decide what to do about the possibility that this can

  137. // report an available-data size that exceeds a Java int’s max

  138. // positive value, causing havoc.  Fortunately this will only

  139. // happen if someone constructs a Parcel containing more than two

  140. // gigabytes of data, which on typical phone hardware is simply

  141. // not possible.

  142. return dataSize() - dataPosition();

  143. }

  144. size_t Parcel::dataPosition() const

  145. {

  146. return mDataPos;

  147. }

  148. size_t Parcel::dataCapacity() const

  149. {

  150. return mDataCapacity;

  151. }

  152. status_t Parcel::setDataSize(size_t size)

  153. {

  154. status_t err;

  155. err = continueWrite(size);

  156. if (err == NO_ERROR) {

  157. mDataSize = size;

  158. LOGV(“setDataSize Setting data size of %p to %d/n”, this, mDataSize);

  159. }

  160. return err;

  161. }

  162. void Parcel::setDataPosition(size_t pos) const

  163. {

  164. mDataPos = pos;

  165. mNextObjectHint = 0;

  166. }

  167. status_t Parcel::setDataCapacity(size_t size)

  168. {

  169. if (size > mDataSize) return continueWrite(size);

  170. return NO_ERROR;

  171. }

  172. status_t Parcel::setData(const uint8_t* buffer, size_t len)

  173. {

  174. status_t err = restartWrite(len);

  175. if (err == NO_ERROR) {

  176. memcpy(const_cast<uint8_t*>(data()), buffer, len);

  177. mDataSize = len;

  178. mFdsKnown = false;

  179. }

  180. return err;

  181. }

  182. status_t Parcel::appendFrom(Parcel *parcel, size_t offset, size_t len)

  183. {

  184. const sp proc(ProcessState::self());

  185. status_t err;

  186. uint8_t *data = parcel->mData;

  187. size_t *objects = parcel->mObjects;

  188. size_t size = parcel->mObjectsSize;

  189. int startPos = mDataPos;

  190. int firstIndex = -1, lastIndex = -2;

  191. if (len == 0) {

  192. return NO_ERROR;

  193. }

  194. // range checks against the source parcel size

  195. if ((offset > parcel->mDataSize)

  196. || (len > parcel->mDataSize)

  197. || (offset + len > parcel->mDataSize)) {

  198. return BAD_VALUE;

  199. }

  200. // Count objects in range

  201. for (int i = 0; i < (int) size; i++) {

  202. size_t off = objects[i];

  203. if ((off >= offset) && (off < offset + len)) {

  204. if (firstIndex == -1) {

  205. firstIndex = i;

  206. }

  207. lastIndex = i;

  208. }

  209. }

  210. int numObjects = lastIndex - firstIndex + 1;

  211. // grow data

  212. err = growData(len);

  213. if (err != NO_ERROR) {

  214. return err;

  215. }

  216. // append data

  217. memcpy(mData + mDataPos, data + offset, len);

  218. mDataPos += len;

  219. mDataSize += len;

  220. if (numObjects > 0) {

  221. // grow objects

  222. if (mObjectsCapacity < mObjectsSize + numObjects) {

  223. int newSize = ((mObjectsSize + numObjects)*3)/2;

  224. size_t *objects =

  225. (size_t*)realloc(mObjects, newSize*sizeof(size_t));

  226. if (objects == (size_t*)0) {

  227. return NO_MEMORY;

  228. }

  229. mObjects = objects;

  230. mObjectsCapacity = newSize;

  231. }

  232. // append and acquire objects

  233. int idx = mObjectsSize;

  234. for (int i = firstIndex; i <= lastIndex; i++) {

  235. size_t off = objects[i] - offset + startPos;

  236. mObjects[idx++] = off;

  237. mObjectsSize++;

  238. flat_binder_object* flat

  239. = reinterpret_cast<flat_binder_object*>(mData + off);

  240. acquire_object(proc, *flat, this);

  241. if (flat->type == BINDER_TYPE_FD) {

  242. // If this is a file descriptor, we need to dup it so the

  243. // new Parcel now owns its own fd, and can declare that we

  244. // officially know we have fds.

  245. flat->handle = dup(flat->handle);

  246. flat->cookie = (void*)1;

  247. mHasFds = mFdsKnown = true;

  248. }

  249. }

  250. }

  251. return NO_ERROR;

  252. }

  253. bool Parcel::hasFileDescriptors() const

  254. {

  255. if (!mFdsKnown) {

  256. scanForFds();

  257. }

  258. return mHasFds;

  259. }

  260. status_t Parcel::writeInterfaceToken(const String16& interface)

  261. {

  262. // currently the interface identification token is just its name as a string

  263. return writeString16(interface);

  264. }

  265. bool Parcel::checkInterface(IBinder* binder) const

  266. {

  267. return enforceInterface(binder->getInterfaceDescriptor());

  268. }

  269. bool Parcel::enforceInterface(const String16& interface) const

  270. {

  271. const String16 str(readString16());

  272. if (str == interface) {

  273. return true;

  274. } else {

  275. LOGW(“**** enforceInterface() expected ‘%s’ but read ‘%s’/n”,

  276. String8(interface).string(), String8(str).string());

  277. return false;

  278. }

  279. }

  280. const size_t* Parcel::objects() const

  281. {

  282. return mObjects;

  283. }

  284. size_t Parcel::objectsCount() const

  285. {

  286. return mObjectsSize;

  287. }

  288. status_t Parcel::errorCheck() const

  289. {

  290. return mError;

  291. }

  292. void Parcel::setError(status_t err)

  293. {

  294. mError = err;

  295. }

  296. status_t Parcel::finishWrite(size_t len)

  297. {

  298. //printf(“Finish write of %d/n”, len);

  299. mDataPos += len;

  300. LOGV(“finishWrite Setting data pos of %p to %d/n”, this, mDataPos);

  301. if (mDataPos > mDataSize) {

  302. mDataSize = mDataPos;

  303. LOGV(“finishWrite Setting data size of %p to %d/n”, this, mDataSize);

  304. }

  305. //printf(“New pos=%d, size=%d/n”, mDataPos, mDataSize);

  306. return NO_ERROR;

  307. }

  308. status_t Parcel::writeUnpadded(const void* data, size_t len)

  309. {

  310. size_t end = mDataPos + len;

  311. if (end < mDataPos) {

  312. // integer overflow

  313. return BAD_VALUE;

  314. }

  315. if (end <= mDataCapacity) {

  316. restart_write:

  317. memcpy(mData+mDataPos, data, len);

  318. return finishWrite(len);

  319. }

  320. status_t err = growData(len);

  321. if (err == NO_ERROR) goto restart_write;

  322. return err;

  323. }

  324. status_t Parcel::write(const void* data, size_t len)

  325. {

  326. void* const d = writeInplace(len);

  327. if (d) {

  328. memcpy(d, data, len);

  329. return NO_ERROR;

  330. }

  331. return mError;

  332. }

  333. void* Parcel::writeInplace(size_t len)

  334. {

  335. const size_t padded = PAD_SIZE(len);

  336. // sanity check for integer overflow

  337. if (mDataPos+padded < mDataPos) {

  338. return NULL;

  339. }

  340. if ((mDataPos+padded) <= mDataCapacity) {

  341. restart_write:

  342. //printf(“Writing %ld bytes, padded to %ld/n”, len, padded);

  343. uint8_t* const data = mData+mDataPos;

  344. // Need to pad at end?

  345. if (padded != len) {

  346. #if BYTE_ORDER == BIG_ENDIAN

  347. static const uint32_t mask[4] = {

  348. 0x00000000, 0xffffff00, 0xffff0000, 0xff000000

  349. };

  350. #endif

  351. #if BYTE_ORDER == LITTLE_ENDIAN

  352. static const uint32_t mask[4] = {

  353. 0x00000000, 0x00ffffff, 0x0000ffff, 0x000000ff

  354. };

  355. #endif

  356. //printf(“Applying pad mask: %p to %p/n”, (void*)mask[padded-len],

  357. //    *reinterpret_cast<void**>(data+padded-4));

  358. *reinterpret_cast<uint32_t*>(data+padded-4) &= mask[padded-len];

  359. }

  360. finishWrite(padded);

  361. return data;

  362. }

  363. status_t err = growData(padded);

  364. if (err == NO_ERROR) goto restart_write;

  365. return NULL;

  366. }

  367. status_t Parcel::writeInt32(int32_t val)

  368. {

  369. return writeAligned(val);

  370. }

  371. status_t Parcel::writeInt64(int64_t val)

  372. {

  373. return writeAligned(val);

  374. }

  375. status_t Parcel::writeFloat(float val)

  376. {

  377. return writeAligned(val);

  378. }

  379. status_t Parcel::writeDouble(double val)

  380. {

  381. return writeAligned(val);

  382. }

  383. status_t Parcel::writeIntPtr(intptr_t val)

  384. {

  385. return writeAligned(val);

  386. }

  387. status_t Parcel::writeCString(const char* str)

  388. {

  389. return write(str, strlen(str)+1);

  390. }

  391. status_t Parcel::writeString8(const String8& str)

  392. {

  393. status_t err = writeInt32(str.bytes());

  394. if (err == NO_ERROR) {

  395. err = write(str.string(), str.bytes()+1);

  396. }

  397. return err;

  398. }

  399. status_t Parcel::writeString16(const String16& str)

  400. {

  401. return writeString16(str.string(), str.size());

  402. }

  403. status_t Parcel::writeString16(const char16_t* str, size_t len)

  404. {

  405. if (str == NULL) return writeInt32(-1);

  406. status_t err = writeInt32(len);

  407. if (err == NO_ERROR) {

  408. len *= sizeof(char16_t);

  409. uint8_t* data = (uint8_t*)writeInplace(len+sizeof(char16_t));

  410. if (data) {

  411. memcpy(data, str, len);

  412. *reinterpret_cast<char16_t*>(data+len) = 0;

  413. return NO_ERROR;

  414. }

  415. err = mError;

  416. }

  417. return err;

  418. }

  419. status_t Parcel::writeStrongBinder(const sp& val)

  420. {

  421. return flatten_binder(ProcessState::self(), val, this);

  422. }

  423. status_t Parcel::writeWeakBinder(const wp& val)

  424. {

  425. return flatten_binder(ProcessState::self(), val, this);

  426. }

  427. status_t Parcel::writeNativeHandle(const native_handle* handle)

  428. {

  429. if (!handle || handle->version != sizeof(native_handle))

  430. return BAD_TYPE;

  431. status_t err;

  432. err = writeInt32(handle->numFds);

  433. if (err != NO_ERROR) return err;

  434. err = writeInt32(handle->numInts);

  435. if (err != NO_ERROR) return err;

  436. for (int i=0 ; err==NO_ERROR && inumFds ; i++)

  437. err = writeDupFileDescriptor(handle->data[i]);

  438. if (err != NO_ERROR) {

  439. LOGD(“write native handle, write dup fd failed”);

  440. return err;

  441. }

  442. err = write(handle->data + handle->numFds, sizeof(int)*handle->numInts);

  443. return err;

  444. }

  445. status_t Parcel::writeFileDescriptor(int fd)

  446. {

  447. flat_binder_object obj;

  448. obj.type = BINDER_TYPE_FD;

  449. obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;

  450. obj.handle = fd;

  451. obj.cookie = (void*)0;

  452. return writeObject(obj, true);

  453. }

  454. status_t Parcel::writeDupFileDescriptor(int fd)

  455. {

  456. flat_binder_object obj;

  457. obj.type = BINDER_TYPE_FD;

  458. obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;

  459. obj.handle = dup(fd);

  460. obj.cookie = (void*)1;

  461. return writeObject(obj, true);

  462. }

  463. status_t Parcel::write(const Flattenable& val)

  464. {

  465. status_t err;

  466. // size if needed

  467. size_t len = val.getFlattenedSize();

  468. size_t fd_count = val.getFdCount();

  469. err = this->writeInt32(len);

  470. if (err) return err;

  471. err = this->writeInt32(fd_count);

  472. if (err) return err;

  473. // payload

  474. void* buf = this->writeInplace(PAD_SIZE(len));

  475. if (buf == NULL)

  476. return BAD_VALUE;

  477. int* fds = NULL;

  478. if (fd_count) {

  479. fds = new int[fd_count];

  480. }

  481. err = val.flatten(buf, len, fds, fd_count);

  482. for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {

  483. err = this->writeDupFileDescriptor( fds[i] );

  484. }

  485. if (fd_count) {

  486. delete [] fds;

  487. }

  488. return err;

  489. }

  490. status_t Parcel::writeObject(const flat_binder_object& val, bool nullMetaData)

  491. {

  492. const bool enoughData = (mDataPos+sizeof(val)) <= mDataCapacity;

  493. const bool enoughObjects = mObjectsSize < mObjectsCapacity;

  494. if (enoughData && enoughObjects) {

  495. restart_write:

  496. *reinterpret_cast<flat_binder_object*>(mData+mDataPos) = val;

  497. // Need to write meta-data?

  498. if (nullMetaData || val.binder != NULL) {

  499. mObjects[mObjectsSize] = mDataPos;

  500. acquire_object(ProcessState::self(), val, this);

  501. mObjectsSize++;

  502. }

  503. // remember if it’s a file descriptor

  504. if (val.type == BINDER_TYPE_FD) {

  505. mHasFds = mFdsKnown = true;

  506. }

  507. return finishWrite(sizeof(flat_binder_object));

  508. }

  509. if (!enoughData) {

  510. const status_t err = growData(sizeof(val));

  511. if (err != NO_ERROR) return err;

  512. }

  513. if (!enoughObjects) {

  514. size_t newSize = ((mObjectsSize+2)*3)/2;

  515. size_t* objects = (size_t*)realloc(mObjects, newSize*sizeof(size_t));

  516. if (objects == NULL) return NO_MEMORY;

  517. mObjects = objects;

  518. mObjectsCapacity = newSize;

  519. }

  520. goto restart_write;

  521. }

  522. void Parcel::remove(size_t start, size_t amt)

  523. {

  524. LOG_ALWAYS_FATAL(“Parcel::remove() not yet implemented!”);

  525. }

  526. status_t Parcel::read(void* outData, size_t len) const

  527. {

  528. if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {

  529. memcpy(outData, mData+mDataPos, len);

  530. mDataPos += PAD_SIZE(len);

  531. LOGV(“read Setting data pos of %p to %d/n”, this, mDataPos);

  532. return NO_ERROR;

  533. }

  534. return NOT_ENOUGH_DATA;

  535. }

  536. const void* Parcel::readInplace(size_t len) const

  537. {

  538. if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize) {

  539. const void* data = mData+mDataPos;

  540. mDataPos += PAD_SIZE(len);

  541. LOGV(“readInplace Setting data pos of %p to %d/n”, this, mDataPos);

  542. return data;

  543. }

  544. return NULL;

  545. }

  546. template

  547. status_t Parcel::readAligned(T *pArg) const {

  548. COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));

  549. if ((mDataPos+sizeof(T)) <= mDataSize) {

  550. const void* data = mData+mDataPos;

  551. mDataPos += sizeof(T);

  552. *pArg =  *reinterpret_cast<const T*>(data);

  553. return NO_ERROR;

  554. } else {

  555. return NOT_ENOUGH_DATA;

  556. }

  557. }

  558. template

  559. T Parcel::readAligned() const {

  560. T result;

  561. if (readAligned(&result) != NO_ERROR) {

  562. result = 0;

  563. }

  564. return result;

  565. }

  566. template

  567. status_t Parcel::writeAligned(T val) {

  568. COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T));

  569. if ((mDataPos+sizeof(val)) <= mDataCapacity) {

  570. restart_write:

  571. *reinterpret_cast<T*>(mData+mDataPos) = val;

  572. return finishWrite(sizeof(val));

  573. }

  574. status_t err = growData(sizeof(val));

  575. if (err == NO_ERROR) goto restart_write;

  576. return err;

  577. }

  578. status_t Parcel::readInt32(int32_t *pArg) const

  579. {

  580. return readAligned(pArg);

  581. }

  582. int32_t Parcel::readInt32() const

  583. {

  584. return readAligned<int32_t>();

  585. }

  586. status_t Parcel::readInt64(int64_t *pArg) const

  587. {

  588. return readAligned(pArg);

  589. }

  590. int64_t Parcel::readInt64() const

  591. {

  592. return readAligned<int64_t>();

  593. }

  594. status_t Parcel::readFloat(float *pArg) const

  595. {

  596. return readAligned(pArg);

  597. }

  598. float Parcel::readFloat() const

  599. {

  600. return readAligned<float>();

  601. }

  602. status_t Parcel::readDouble(double *pArg) const

  603. {

  604. return readAligned(pArg);

  605. }

  606. double Parcel::readDouble() const

  607. {

  608. return readAligned<double>();

  609. }

  610. status_t Parcel::readIntPtr(intptr_t *pArg) const

  611. {

  612. return readAligned(pArg);

  613. }

  614. intptr_t Parcel::readIntPtr() const

  615. {

  616. return readAligned<intptr_t>();

  617. }

  618. const char* Parcel::readCString() const

  619. {

  620. const size_t avail = mDataSize-mDataPos;

  621. if (avail > 0) {

  622. const char* str = reinterpret_cast<const char*>(mData+mDataPos);

  623. // is the string’s trailing NUL within the parcel’s valid bounds?

  624. const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail));

  625. if (eos) {

  626. const size_t len = eos - str;

  627. mDataPos += PAD_SIZE(len+1);

  628. LOGV(“readCString Setting data pos of %p to %d/n”, this, mDataPos);

  629. return str;

  630. }

  631. }

  632. return NULL;

  633. }

  634. String8 Parcel::readString8() const

  635. {

  636. int32_t size = readInt32();

  637. // watch for potential int overflow adding 1 for trailing NUL

  638. if (size > 0 && size < INT32_MAX) {

  639. const char* str = (const char*)readInplace(size+1);

  640. if (str) return String8(str, size);

  641. }

  642. return String8();

  643. }

  644. String16 Parcel::readString16() const

  645. {

  646. size_t len;

  647. const char16_t* str = readString16Inplace(&len);

  648. if (str) return String16(str, len);

  649. LOGE(“Reading a NULL string not supported here.”);

  650. return String16();

  651. }

  652. const char16_t* Parcel::readString16Inplace(size_t* outLen) const

  653. {

  654. int32_t size = readInt32();

  655. // watch for potential int overflow from size+1

  656. if (size >= 0 && size < INT32_MAX) {

  657. *outLen = size;

  658. const char16_t* str = (const char16_t*)readInplace((size+1)*sizeof(char16_t));

  659. if (str != NULL) {

  660. return str;

  661. }

  662. }

  663. *outLen = 0;

  664. return NULL;

  665. }

  666. sp Parcel::readStrongBinder() const

  667. {

  668. sp val;

  669. unflatten_binder(ProcessState::self(), *this, &val);

  670. return val;

  671. }

  672. wp Parcel::readWeakBinder() const

  673. {

  674. wp val;

  675. unflatten_binder(ProcessState::self(), *this, &val);

  676. return val;

  677. }

  678. native_handle* Parcel::readNativeHandle() const

  679. {

  680. int numFds, numInts;

  681. status_t err;

  682. err = readInt32(&numFds);

  683. if (err != NO_ERROR) return 0;

  684. err = readInt32(&numInts);

  685. if (err != NO_ERROR) return 0;

  686. native_handle* h = native_handle_create(numFds, numInts);

  687. for (int i=0 ; err==NO_ERROR && i<numFds ; i++) {

  688. h->data[i] = dup(readFileDescriptor());

  689. if (h->data[i] < 0) err = BAD_VALUE;

  690. }

  691. err = read(h->data + numFds, sizeof(int)*numInts);

  692. if (err != NO_ERROR) {

  693. native_handle_close(h);

  694. native_handle_delete(h);

  695. h = 0;

  696. }

  697. return h;

  698. }

  699. int Parcel::readFileDescriptor() const

  700. {

  701. const flat_binder_object* flat = readObject(true);

  702. if (flat) {

  703. switch (flat->type) {

  704. case BINDER_TYPE_FD:

  705. //LOGI(“Returning file descriptor %ld from parcel %p/n”, flat->handle, this);

  706. return flat->handle;

  707. }

  708. }

  709. return BAD_TYPE;

  710. }

  711. status_t Parcel::read(Flattenable& val) const

  712. {

  713. // size

  714. const size_t len = this->readInt32();

  715. const size_t fd_count = this->readInt32();

  716. // payload

  717. void const* buf = this->readInplace(PAD_SIZE(len));

  718. if (buf == NULL)

  719. return BAD_VALUE;

  720. int* fds = NULL;

  721. if (fd_count) {

  722. fds = new int[fd_count];

  723. }

  724. status_t err = NO_ERROR;

  725. for (size_t i=0 ; i<fd_count && err==NO_ERROR ; i++) {

  726. fds[i] = dup(this->readFileDescriptor());

  727. if (fds[i] < 0) err = BAD_VALUE;

  728. }

  729. if (err == NO_ERROR) {

  730. err = val.unflatten(buf, len, fds, fd_count);

  731. }

  732. if (fd_count) {

  733. delete [] fds;

  734. }

  735. return err;

  736. }

  737. const flat_binder_object* Parcel::readObject(bool nullMetaData) const

  738. {

  739. const size_t DPOS = mDataPos;

  740. if ((DPOS+sizeof(flat_binder_object)) <= mDataSize) {

  741. const flat_binder_object* obj

  742. = reinterpret_cast<const flat_binder_object*>(mData+DPOS);

  743. mDataPos = DPOS + sizeof(flat_binder_object);

  744. if (!nullMetaData && (obj->cookie == NULL && obj->binder == NULL)) {

  745. // When transferring a NULL object, we don’t write it into

  746. // the object list, so we don’t want to check for it when

  747. // reading.

  748. LOGV(“readObject Setting data pos of %p to %d/n”, this, mDataPos);

  749. return obj;

  750. }

  751. // Ensure that this object is valid…

  752. size_t* const OBJS = mObjects;

  753. const size_t N = mObjectsSize;

  754. size_t opos = mNextObjectHint;

  755. if (N > 0) {

  756. LOGV(“Parcel %p looking for obj at %d, hint=%d/n”,

  757. this, DPOS, opos);

  758. // Start at the current hint position, looking for an object at

  759. // the current data position.

  760. if (opos < N) {

  761. while (opos < (N-1) && OBJS[opos] < DPOS) {

  762. opos++;

  763. }

  764. } else {

  765. opos = N-1;

  766. }

  767. if (OBJS[opos] == DPOS) {

  768. // Found it!

  769. LOGV(“Parcel found obj %d at index %d with forward search”,

  770. this, DPOS, opos);

  771. mNextObjectHint = opos+1;

  772. LOGV(“readObject Setting data pos of %p to %d/n”, this, mDataPos);

  773. return obj;

  774. }

  775. // Look backwards for it…

  776. while (opos > 0 && OBJS[opos] > DPOS) {

  777. opos–;

  778. }

  779. if (OBJS[opos] == DPOS) {

  780. // Found it!

  781. LOGV(“Parcel found obj %d at index %d with backward search”,

  782. this, DPOS, opos);

  783. mNextObjectHint = opos+1;

  784. LOGV(“readObject Setting data pos of %p to %d/n”, this, mDataPos);

  785. return obj;

  786. }

  787. }

  788. LOGW(“Attempt to read object from Parcel %p at offset %d that is not in the object list”,

  789. this, DPOS);

  790. }

  791. return NULL;

  792. }

  793. void Parcel::closeFileDescriptors()

  794. {

  795. size_t i = mObjectsSize;

  796. if (i > 0) {

  797. //LOGI(“Closing file descriptors for %d objects…”, mObjectsSize);

  798. }

  799. while (i > 0) {

  800. i–;

  801. const flat_binder_object* flat

  802. = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);

  803. if (flat->type == BINDER_TYPE_FD) {

  804. //LOGI(“Closing fd: %ld/n”, flat->handle);

  805. close(flat->handle);

  806. }

  807. }

  808. }

  809. const uint8_t* Parcel::ipcData() const

  810. {

  811. return mData;

  812. }

  813. size_t Parcel::ipcDataSize() const

  814. {

  815. return (mDataSize > mDataPos ? mDataSize : mDataPos);

  816. }

  817. const size_t* Parcel::ipcObjects() const

  818. {

  819. return mObjects;

  820. }

  821. size_t Parcel::ipcObjectsCount() const

  822. {

  823. return mObjectsSize;

  824. }

  825. void Parcel::ipcSetDataReference(const uint8_t* data, size_t dataSize,

  826. const size_t* objects, size_t objectsCount, release_func relFunc, void* relCookie)

  827. {

  828. freeDataNoInit();

  829. mError = NO_ERROR;

  830. mData = const_cast<uint8_t*>(data);

  831. mDataSize = mDataCapacity = dataSize;

  832. //LOGI(“setDataReference Setting data size of %p to %lu (pid=%d)/n”, this, mDataSize, getpid());

  833. mDataPos = 0;

  834. LOGV(“setDataReference Setting data pos of %p to %d/n”, this, mDataPos);

  835. mObjects = const_cast<size_t*>(objects);

  836. mObjectsSize = mObjectsCapacity = objectsCount;

  837. mNextObjectHint = 0;

  838. mOwner = relFunc;

  839. mOwnerCookie = relCookie;

  840. scanForFds();

  841. }

  842. void Parcel::print(TextOutput& to, uint32_t flags) const

  843. {

  844. to << “Parcel(”;

  845. if (errorCheck() != NO_ERROR) {

  846. const status_t err = errorCheck();

  847. to << “Error: " << (void*)err << " /”" << strerror(-err) << “/”";

  848. } else if (dataSize() > 0) {

  849. const uint8_t* DATA = data();

  850. to << indent << HexDump(DATA, dataSize()) << dedent;

  851. const size_t* OBJS = objects();

  852. const size_t N = objectsCount();

  853. for (size_t i=0; i<N; i++) {

  854. const flat_binder_object* flat

  855. = reinterpret_cast<const flat_binder_object*>(DATA+OBJS[i]);

  856. to << endl << “Object #” << i << " @ " << (void*)OBJS[i] << ": "

  857. << TypeCode(flat->type & 0x7f7f7f00)

  858. << " = " << flat->binder;

  859. }

  860. } else {

  861. to << “NULL”;

  862. }

  863. to << “)”;

  864. }

  865. void Parcel::releaseObjects()

  866. {

  867. const sp proc(ProcessState::self());

  868. size_t i = mObjectsSize;

  869. uint8_t* const data = mData;

  870. size_t* const objects = mObjects;

  871. while (i > 0) {

  872. i–;

  873. const flat_binder_object* flat

  874. = reinterpret_cast<flat_binder_object*>(data+objects[i]);

  875. release_object(proc, *flat, this);

  876. }

  877. }

  878. void Parcel::acquireObjects()

  879. {

  880. const sp proc(ProcessState::self());

  881. size_t i = mObjectsSize;

  882. uint8_t* const data = mData;

  883. size_t* const objects = mObjects;

  884. while (i > 0) {

  885. i–;

  886. const flat_binder_object* flat

  887. = reinterpret_cast<flat_binder_object*>(data+objects[i]);

  888. acquire_object(proc, *flat, this);

  889. }

  890. }

  891. void Parcel::freeData()

  892. {

  893. freeDataNoInit();

  894. initState();

  895. }

  896. void Parcel::freeDataNoInit()

  897. {

  898. if (mOwner) {

  899. //LOGI(“Freeing data ref of %p (pid=%d)/n”, this, getpid());

  900. mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);

  901. } else {

  902. releaseObjects();

  903. if (mData) free(mData);

  904. if (mObjects) free(mObjects);

  905. }

  906. }

  907. status_t Parcel::growData(size_t len)

  908. {

  909. size_t newSize = ((mDataSize+len)*3)/2;

  910. return (newSize <= mDataSize)

  911. ? (status_t) NO_MEMORY

  912. : continueWrite(newSize);

  913. }

  914. status_t Parcel::restartWrite(size_t desired)

  915. {

  916. if (mOwner) {

  917. freeData();

  918. return continueWrite(desired);

  919. }

  920. uint8_t* data = (uint8_t*)realloc(mData, desired);

  921. if (!data && desired > mDataCapacity) {

  922. mError = NO_MEMORY;

  923. return NO_MEMORY;

  924. }

  925. releaseObjects();

  926. if (data) {

  927. mData = data;

  928. mDataCapacity = desired;

  929. }

  930. mDataSize = mDataPos = 0;

  931. LOGV(“restartWrite Setting data size of %p to %d/n”, this, mDataSize);

  932. LOGV(“restartWrite Setting data pos of %p to %d/n”, this, mDataPos);

  933. free(mObjects);

  934. mObjects = NULL;

  935. mObjectsSize = mObjectsCapacity = 0;

  936. mNextObjectHint = 0;

  937. mHasFds = false;

  938. mFdsKnown = true;

  939. return NO_ERROR;

  940. }

  941. status_t Parcel::continueWrite(size_t desired)

  942. {

  943. // If shrinking, first adjust for any objects that appear

  944. // after the new data size.

  945. size_t objectsSize = mObjectsSize;

  946. if (desired < mDataSize) {

  947. if (desired == 0) {

  948. objectsSize = 0;

  949. } else {

  950. while (objectsSize > 0) {

  951. if (mObjects[objectsSize-1] < desired)

  952. break;

  953. objectsSize–;

  954. }

  955. }

  956. }

  957. if (mOwner) {

  958. // If the size is going to zero, just release the owner’s data.

  959. if (desired == 0) {

  960. freeData();

  961. return NO_ERROR;

  962. }

  963. // If there is a different owner, we need to take

  964. // posession.

  965. uint8_t* data = (uint8_t*)malloc(desired);

  966. if (!data) {

  967. mError = NO_MEMORY;

  968. return NO_MEMORY;

  969. }

  970. size_t* objects = NULL;

  971. if (objectsSize) {

  972. objects = (size_t*)malloc(objectsSize*sizeof(size_t));

  973. if (!objects) {

  974. mError = NO_MEMORY;

  975. return NO_MEMORY;

  976. }

  977. // Little hack to only acquire references on objects

  978. // we will be keeping.

  979. size_t oldObjectsSize = mObjectsSize;

  980. mObjectsSize = objectsSize;

  981. acquireObjects();

  982. mObjectsSize = oldObjectsSize;

  983. }

  984. if (mData) {

  985. memcpy(data, mData, mDataSize < desired ? mDataSize : desired);

  986. }

  987. if (objects && mObjects) {

  988. memcpy(objects, mObjects, objectsSize*sizeof(size_t));

  989. }

  990. //LOGI(“Freeing data ref of %p (pid=%d)/n”, this, getpid());

  991. mOwner(this, mData, mDataSize, mObjects, mObjectsSize, mOwnerCookie);

  992. mOwner = NULL;

  993. mData = data;

  994. mObjects = objects;

  995. mDataSize = (mDataSize < desired) ? mDataSize : desired;

  996. LOGV(“continueWrite Setting data size of %p to %d/n”, this, mDataSize);

  997. mDataCapacity = desired;

  998. mObjectsSize = mObjectsCapacity = objectsSize;

  999. mNextObjectHint = 0;

  1000. } else if (mData) {

  1001. if (objectsSize < mObjectsSize) {

  1002. // Need to release refs on any objects we are dropping.

  1003. const sp proc(ProcessState::self());

  1004. for (size_t i=objectsSize; i<mObjectsSize; i++) {

  1005. const flat_binder_object* flat

  1006. = reinterpret_cast<flat_binder_object*>(mData+mObjects[i]);

  1007. if (flat->type == BINDER_TYPE_FD) {

  1008. // will need to rescan because we may have lopped off the only FDs

  1009. mFdsKnown = false;

  1010. }

  1011. release_object(proc, *flat, this);

  1012. }

  1013. size_t* objects =

  1014. (size_t*)realloc(mObjects, objectsSize*sizeof(size_t));

  1015. if (objects) {

  1016. mObjects = objects;

  1017. }

  1018. mObjectsSize = objectsSize;

  1019. mNextObjectHint = 0;

  1020. }

  1021. // We own the data, so we can just do a realloc().

  1022. if (desired > mDataCapacity) {

  1023. uint8_t* data = (uint8_t*)realloc(mData, desired);

  1024. if (data) {

  1025. mData = data;

  1026. mDataCapacity = desired;

  1027. } else if (desired > mDataCapacity) {

  1028. mError = NO_MEMORY;

  1029. return NO_MEMORY;

  1030. }

  1031. } else {

  1032. mDataSize = desired;

  1033. LOGV(“continueWrite Setting data size of %p to %d/n”, this, mDataSize);

  1034. if (mDataPos > desired) {

  1035. mDataPos = desired;

  1036. LOGV(“continueWrite Setting data pos of %p to %d/n”, this, mDataPos);

  1037. }

  1038. }

  1039. } else {

  1040. // This is the first data.  Easy!

  1041. uint8_t* data = (uint8_t*)malloc(desired);

  1042. if (!data) {

  1043. mError = NO_MEMORY;

  1044. return NO_MEMORY;

  1045. }

  1046. if(!(mDataCapacity == 0 && mObjects == NULL

  1047. && mObjectsCapacity == 0)) {

  1048. LOGE(“continueWrite: %d/%p/%d/%d”, mDataCapacity, mObjects, mObjectsCapacity, desired);

  1049. }

  1050. mData = data;

  1051. mDataSize = mDataPos = 0;

  1052. LOGV(“continueWrite Setting data size of %p to %d/n”, this, mDataSize);

  1053. LOGV(“continueWrite Setting data pos of %p to %d/n”, this, mDataPos);

  1054. mDataCapacity = desired;

  1055. }

  1056. return NO_ERROR;

  1057. }

  1058. void Parcel::initState()

  1059. {

  1060. mError = NO_ERROR;

  1061. mData = 0;

  1062. mDataSize = 0;

  1063. mDataCapacity = 0;

  1064. mDataPos = 0;

  1065. LOGV(“initState Setting data size of %p to %d/n”, this, mDataSize);

  1066. LOGV(“initState Setting data pos of %p to %d/n”, this, mDataPos);

  1067. mObjects = NULL;

  1068. mObjectsSize = 0;

  1069. mObjectsCapacity = 0;

  1070. mNextObjectHint = 0;

  1071. mHasFds = false;

  1072. mFdsKnown = true;

  1073. mOwner = NULL;

  1074. }

  1075. void Parcel::scanForFds() const

  1076. {

  1077. bool hasFds = false;

  1078. for (size_t i=0; i<mObjectsSize; i++) {

  1079. const flat_binder_object* flat

  1080. = reinterpret_cast<const flat_binder_object*>(mData + mObjects[i]);

  1081. if (flat->type == BINDER_TYPE_FD) {

  1082. hasFds = true;

  1083. break;

  1084. }

  1085. }

  1086. mHasFds = hasFds;

  1087. mFdsKnown = true;

  1088. }

  1089. }; // namespace android

本文的源码使用的是Android 2.1版本。

上一篇中我们透过源码看到了Parcel背后的机制,本质上把它当成一个Serialize就可以了,只是它是在内存中完成的序列化和反序列化,利用的是连续的内存空间,因此会更加高效。

我们接下来要说的是Parcel类如何应用。就应用程序而言,最常见使用Parcel类的场景就是在Activity间传递数据。没错,在Activity间使用Intent传递数据的时候,可以通过Parcelable机制传递复杂的对象。

在下面的程序中,MyColor用于保存一个颜色值,MainActivity在用户点击屏幕时将MyColor对象设成红色,传递到SubActivity中,此时SubActivity的TextView显示为红色的背景;当点击SubActivity时,将颜色值改为绿色,返回MainActivity,期望的是MainActivity的TextView显示绿色背景。

来看一下MyColor类的实现代码:

[java]  view plain copy

  1. package com.wenbin.test;

  2. import android.graphics.Color;

  3. import android.os.Parcel;

  4. import android.os.Parcelable;

  5. /**

  6. * @author 曹文斌

  7. * http://blog.csdn.net/caowenbin

  8. *

  9. */

  10. public class MyColor implements Parcelable {

  11. private int color=Color.BLACK;

  12. MyColor(){

  13. color=Color.BLACK;

  14. }

  15. MyColor(Parcel in){

  16. color=in.readInt();

  17. }

  18. public int getColor(){

  19. return color;

  20. }

  21. public void setColor(int color){

  22. this.color=color;

  23. }

  24. @Override

  25. public int describeContents() {

  26. return 0;

  27. }

  28. @Override

  29. public void writeToParcel(Parcel dest, int flags) {

  30. dest.writeInt(color);

  31. }

  32. public static final Parcelable.Creator CREATOR

  33. = new Parcelable.Creator() {

  34. public MyColor createFromParcel(Parcel in) {

  35. return new MyColor(in);

  36. }

  37. public MyColor[] newArray(int size) {

  38. return new MyColor[size];

  39. }

  40. };

  41. }

该类实现了Parcelable接口,提供了默认的构造函数,同时也提供了可从Parcel对象开始的构造函数,另外还实现了一个static的构造器用于构造对象和数组。代码很简单,不一一解释了。

再看MainActivity的代码:

[java]  view plain copy

  1. package com.wenbin.test;

  2. import android.app.Activity;

  3. import android.content.Intent;

  4. import android.graphics.Color;

  5. import android.os.Bundle;

  6. import android.view.MotionEvent;

  7. /**

  8. * @author 曹文斌

  9. * http://blog.csdn.net/caowenbin

  10. *

  11. */

  12. public class MainActivity extends Activity {

  13. private final int SUB_ACTIVITY=0;

  14. private MyColor color=new MyColor();

  15. @Override

  16. public void onCreate(Bundle savedInstanceState) {

  17. super.onCreate(savedInstanceState);

  18. setContentView(R.layout.main);

  19. }

  20. @Override

  21. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

更多Android高级工程师进阶学习资料

进阶学习视频

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

@Override

  1. public void writeToParcel(Parcel dest, int flags) {

  2. dest.writeInt(color);

  3. }

  4. public static final Parcelable.Creator CREATOR

  5. = new Parcelable.Creator() {

  6. public MyColor createFromParcel(Parcel in) {

  7. return new MyColor(in);

  8. }

  9. public MyColor[] newArray(int size) {

  10. return new MyColor[size];

  11. }

  12. };

  13. }

该类实现了Parcelable接口,提供了默认的构造函数,同时也提供了可从Parcel对象开始的构造函数,另外还实现了一个static的构造器用于构造对象和数组。代码很简单,不一一解释了。

再看MainActivity的代码:

[java]  view plain copy

  1. package com.wenbin.test;

  2. import android.app.Activity;

  3. import android.content.Intent;

  4. import android.graphics.Color;

  5. import android.os.Bundle;

  6. import android.view.MotionEvent;

  7. /**

  8. * @author 曹文斌

  9. * http://blog.csdn.net/caowenbin

  10. *

  11. */

  12. public class MainActivity extends Activity {

  13. private final int SUB_ACTIVITY=0;

  14. private MyColor color=new MyColor();

  15. @Override

  16. public void onCreate(Bundle savedInstanceState) {

  17. super.onCreate(savedInstanceState);

  18. setContentView(R.layout.main);

  19. }

  20. @Override

  21. protected void onActivityResult(int requestCode, int resultCode, Intent data) {  
    自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-1SXjxuVY-1713786849009)]

[外链图片转存中…(img-E46V1hzt-1713786849011)]

[外链图片转存中…(img-d4BwJoWV-1713786849012)]

[外链图片转存中…(img-qMbYwmrP-1713786849013)]

[外链图片转存中…(img-p7WK8ziC-1713786849014)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

[外链图片转存中…(img-zKqUcegJ-1713786849015)]

更多Android高级工程师进阶学习资料

进阶学习视频
[外链图片转存中…(img-rxgGxNRU-1713786849017)]

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-cWADbeU9-1713786849018)]

里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值