PageRenderTime 37ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/dalvik/dexgen/src/com/android/dexgen/dex/file/MixedItemSection.java

https://gitlab.com/brian0218/rk3188_r-box_android4.2.2_sdk
Java | 362 lines | 202 code | 57 blank | 103 comment | 31 complexity | 9413f53420270371f95161547e7ec6a5 MD5 | raw file
  1. /*
  2. * Copyright (C) 2007 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.android.dexgen.dex.file;
  17. import com.android.dexgen.util.AnnotatedOutput;
  18. import com.android.dexgen.util.ExceptionWithContext;
  19. import com.android.dexgen.util.Hex;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.Collection;
  23. import java.util.Collections;
  24. import java.util.Comparator;
  25. import java.util.HashMap;
  26. import java.util.Map;
  27. import java.util.NoSuchElementException;
  28. import java.util.TreeMap;
  29. /**
  30. * A section of a {@code .dex} file which consists of a sequence of
  31. * {@link OffsettedItem} objects, which may each be of a different concrete
  32. * class and/or size.
  33. *
  34. * <b>Note:</b> It is invalid for an item in an instance of this class to
  35. * have a larger alignment requirement than the alignment of this instance.
  36. */
  37. public final class MixedItemSection extends Section {
  38. static enum SortType {
  39. /** no sorting */
  40. NONE,
  41. /** sort by type only */
  42. TYPE,
  43. /** sort in class-major order, with instances sorted per-class */
  44. INSTANCE;
  45. };
  46. /** {@code non-null;} sorter which sorts instances by type */
  47. private static final Comparator<OffsettedItem> TYPE_SORTER =
  48. new Comparator<OffsettedItem>() {
  49. public int compare(OffsettedItem item1, OffsettedItem item2) {
  50. ItemType type1 = item1.itemType();
  51. ItemType type2 = item2.itemType();
  52. return type1.compareTo(type2);
  53. }
  54. };
  55. /** {@code non-null;} the items in this part */
  56. private final ArrayList<OffsettedItem> items;
  57. /** {@code non-null;} items that have been explicitly interned */
  58. private final HashMap<OffsettedItem, OffsettedItem> interns;
  59. /** {@code non-null;} how to sort the items */
  60. private final SortType sort;
  61. /**
  62. * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
  63. * if not yet calculated
  64. */
  65. private int writeSize;
  66. /**
  67. * Constructs an instance. The file offset is initially unknown.
  68. *
  69. * @param name {@code null-ok;} the name of this instance, for annotation
  70. * purposes
  71. * @param file {@code non-null;} file that this instance is part of
  72. * @param alignment {@code > 0;} alignment requirement for the final output;
  73. * must be a power of 2
  74. * @param sort how the items should be sorted in the final output
  75. */
  76. public MixedItemSection(String name, DexFile file, int alignment,
  77. SortType sort) {
  78. super(name, file, alignment);
  79. this.items = new ArrayList<OffsettedItem>(100);
  80. this.interns = new HashMap<OffsettedItem, OffsettedItem>(100);
  81. this.sort = sort;
  82. this.writeSize = -1;
  83. }
  84. /** {@inheritDoc} */
  85. @Override
  86. public Collection<? extends Item> items() {
  87. return items;
  88. }
  89. /** {@inheritDoc} */
  90. @Override
  91. public int writeSize() {
  92. throwIfNotPrepared();
  93. return writeSize;
  94. }
  95. /** {@inheritDoc} */
  96. @Override
  97. public int getAbsoluteItemOffset(Item item) {
  98. OffsettedItem oi = (OffsettedItem) item;
  99. return oi.getAbsoluteOffset();
  100. }
  101. /**
  102. * Gets the size of this instance, in items.
  103. *
  104. * @return {@code >= 0;} the size
  105. */
  106. public int size() {
  107. return items.size();
  108. }
  109. /**
  110. * Writes the portion of the file header that refers to this instance.
  111. *
  112. * @param out {@code non-null;} where to write
  113. */
  114. public void writeHeaderPart(AnnotatedOutput out) {
  115. throwIfNotPrepared();
  116. if (writeSize == -1) {
  117. throw new RuntimeException("write size not yet set");
  118. }
  119. int sz = writeSize;
  120. int offset = (sz == 0) ? 0 : getFileOffset();
  121. String name = getName();
  122. if (name == null) {
  123. name = "<unnamed>";
  124. }
  125. int spaceCount = 15 - name.length();
  126. char[] spaceArr = new char[spaceCount];
  127. Arrays.fill(spaceArr, ' ');
  128. String spaces = new String(spaceArr);
  129. if (out.annotates()) {
  130. out.annotate(4, name + "_size:" + spaces + Hex.u4(sz));
  131. out.annotate(4, name + "_off: " + spaces + Hex.u4(offset));
  132. }
  133. out.writeInt(sz);
  134. out.writeInt(offset);
  135. }
  136. /**
  137. * Adds an item to this instance. This will in turn tell the given item
  138. * that it has been added to this instance. It is invalid to add the
  139. * same item to more than one instance, nor to add the same items
  140. * multiple times to a single instance.
  141. *
  142. * @param item {@code non-null;} the item to add
  143. */
  144. public void add(OffsettedItem item) {
  145. throwIfPrepared();
  146. try {
  147. if (item.getAlignment() > getAlignment()) {
  148. throw new IllegalArgumentException(
  149. "incompatible item alignment");
  150. }
  151. } catch (NullPointerException ex) {
  152. // Elucidate the exception.
  153. throw new NullPointerException("item == null");
  154. }
  155. items.add(item);
  156. }
  157. /**
  158. * Interns an item in this instance, returning the interned instance
  159. * (which may not be the one passed in). This will add the item if no
  160. * equal item has been added.
  161. *
  162. * @param item {@code non-null;} the item to intern
  163. * @return {@code non-null;} the equivalent interned instance
  164. */
  165. public <T extends OffsettedItem> T intern(T item) {
  166. throwIfPrepared();
  167. OffsettedItem result = interns.get(item);
  168. if (result != null) {
  169. return (T) result;
  170. }
  171. add(item);
  172. interns.put(item, item);
  173. return item;
  174. }
  175. /**
  176. * Gets an item which was previously interned.
  177. *
  178. * @param item {@code non-null;} the item to look for
  179. * @return {@code non-null;} the equivalent already-interned instance
  180. */
  181. public <T extends OffsettedItem> T get(T item) {
  182. throwIfNotPrepared();
  183. OffsettedItem result = interns.get(item);
  184. if (result != null) {
  185. return (T) result;
  186. }
  187. throw new NoSuchElementException(item.toString());
  188. }
  189. /**
  190. * Writes an index of contents of the items in this instance of the
  191. * given type. If there are none, this writes nothing. If there are any,
  192. * then the index is preceded by the given intro string.
  193. *
  194. * @param out {@code non-null;} where to write to
  195. * @param itemType {@code non-null;} the item type of interest
  196. * @param intro {@code non-null;} the introductory string for non-empty indices
  197. */
  198. public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType,
  199. String intro) {
  200. throwIfNotPrepared();
  201. TreeMap<String, OffsettedItem> index =
  202. new TreeMap<String, OffsettedItem>();
  203. for (OffsettedItem item : items) {
  204. if (item.itemType() == itemType) {
  205. String label = item.toHuman();
  206. index.put(label, item);
  207. }
  208. }
  209. if (index.size() == 0) {
  210. return;
  211. }
  212. out.annotate(0, intro);
  213. for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) {
  214. String label = entry.getKey();
  215. OffsettedItem item = entry.getValue();
  216. out.annotate(0, item.offsetString() + ' ' + label + '\n');
  217. }
  218. }
  219. /** {@inheritDoc} */
  220. @Override
  221. protected void prepare0() {
  222. DexFile file = getFile();
  223. /*
  224. * It's okay for new items to be added as a result of an
  225. * addContents() call; we just have to deal with the possibility.
  226. */
  227. int i = 0;
  228. for (;;) {
  229. int sz = items.size();
  230. if (i >= sz) {
  231. break;
  232. }
  233. for (/*i*/; i < sz; i++) {
  234. OffsettedItem one = items.get(i);
  235. one.addContents(file);
  236. }
  237. }
  238. }
  239. /**
  240. * Places all the items in this instance at particular offsets. This
  241. * will call {@link OffsettedItem#place} on each item. If an item
  242. * does not know its write size before the call to {@code place},
  243. * it is that call which is responsible for setting the write size.
  244. * This method may only be called once per instance; subsequent calls
  245. * will throw an exception.
  246. */
  247. public void placeItems() {
  248. throwIfNotPrepared();
  249. switch (sort) {
  250. case INSTANCE: {
  251. Collections.sort(items);
  252. break;
  253. }
  254. case TYPE: {
  255. Collections.sort(items, TYPE_SORTER);
  256. break;
  257. }
  258. }
  259. int sz = items.size();
  260. int outAt = 0;
  261. for (int i = 0; i < sz; i++) {
  262. OffsettedItem one = items.get(i);
  263. try {
  264. int placedAt = one.place(this, outAt);
  265. if (placedAt < outAt) {
  266. throw new RuntimeException("bogus place() result for " +
  267. one);
  268. }
  269. outAt = placedAt + one.writeSize();
  270. } catch (RuntimeException ex) {
  271. throw ExceptionWithContext.withContext(ex,
  272. "...while placing " + one);
  273. }
  274. }
  275. writeSize = outAt;
  276. }
  277. /** {@inheritDoc} */
  278. @Override
  279. protected void writeTo0(AnnotatedOutput out) {
  280. boolean annotates = out.annotates();
  281. boolean first = true;
  282. DexFile file = getFile();
  283. int at = 0;
  284. for (OffsettedItem one : items) {
  285. if (annotates) {
  286. if (first) {
  287. first = false;
  288. } else {
  289. out.annotate(0, "\n");
  290. }
  291. }
  292. int alignMask = one.getAlignment() - 1;
  293. int writeAt = (at + alignMask) & ~alignMask;
  294. if (at != writeAt) {
  295. out.writeZeroes(writeAt - at);
  296. at = writeAt;
  297. }
  298. one.writeTo(file, out);
  299. at += one.writeSize();
  300. }
  301. if (at != writeSize) {
  302. throw new RuntimeException("output size mismatch");
  303. }
  304. }
  305. }