@@ -20,6 +30,7 @@
diff --git a/tools/ota_analysis/src/services/map_parser.js b/tools/ota_analysis/src/services/map_parser.js
new file mode 100644
index 000000000..f19e24f45
--- /dev/null
+++ b/tools/ota_analysis/src/services/map_parser.js
@@ -0,0 +1,119 @@
+/**
+ * @fileoverview Class MapParser will take in a Android build and construct
+ * several file name maps (physical address: file name) according to it.
+ * The map of each partitions is added by calling MapParser.add(partitionName).
+ * You can query the file name being operated by calling
+ * MapParser.query(address, datalength).
+ */
+
+import * as zip from '@zip.js/zip.js/dist/zip-full.min.js'
+
+export class MapParser {
+ /**
+ * This class will take in a .zip Android build and construct a file type map
+ * @param {File} targetFile
+ */
+ constructor(targetFile) {
+ this.build = new zip.ZipReader(new zip.BlobReader(targetFile))
+ this.mapFiles = new Map()
+ this.maps = new Map()
+ }
+
+ /**
+ * Find the .map entries in the .zip build file. Store them as a map with
+ * pairs of (partition name: zip.js entry).
+ */
+ async init() {
+ let /** Array */ entries = await this.build.getEntries()
+ const /** RegExp*/ regexPath = /IMAGES\/[a-z_]*\.map/g;
+ const /** RegExp*/ regexName = /[\w_]+(?=\.map)/g
+ entries.forEach((entry) => {
+ if (entry.filename.match(regexPath)) {
+ this.mapFiles.set(entry.filename.match(regexName)[0], entry)
+ }
+ });
+ }
+
+ /**
+ * According to the .map in the build, build a map for later query.
+ * @param {String} partitionName
+ * @param {Number} totalLength
+ */
+ async add(partitionName, totalLength) {
+ let /** Array */ map = []
+ const /** RegExp */ regexNumber = /(? */fileEntries = mapText.split('\n')
+ // Each line of the .map file in Android build starts with the filename
+ // Followed by the block address, either a number or a range, for example:
+ // //system/apex/com.android.adbd.apex 54-66 66 66-2663
+ for (let entry of fileEntries) {
+ let /** Array */ elements = entry.split(' ')
+ for (let j = 1; j < elements.length; j++) {
+ let /** Number */ left = 0
+ let /** Number */ right = 0
+ if (elements[j].match(regexRange)) {
+ left = parseInt(elements[j].match(/\d+/g)[0])
+ right = parseInt(elements[j].match(/\d+/g)[1])
+ } else {
+ left = parseInt(elements[j].match(regexNumber))
+ right = parseInt(elements[j].match(regexNumber))
+ }
+ InsertMap(map, elements[0], left, right)
+ }
+ }
+ this.maps.set(partitionName, map)
+ }
+ else {
+ this.maps.set(partitionName, map)
+ }
+ }
+
+ /**
+ * Return the filename of given address.
+ * @param {String} partitionName
+ * @param {Array} extents
+ * @return {Array}
+ */
+ query(partitionName, extents) {
+ let /** Array */ names = []
+ let /** Array */ map = this.maps.get(partitionName)
+ for (let ext of extents) {
+ names.push(queryMap(map,
+ ext.startBlock,
+ ext.startBlock + ext.numBlocks))
+ }
+ return names
+ }
+}
+
+/**
+ * Fill in the hashtable from to using .
+ * @param {Array} map
+ * @param {String} name
+ * @param {Number} left
+ * @param {Number} right
+ */
+function InsertMap(map, name, left, right) {
+ for (let i = left; i <= right; i++) {
+ map[i] = name
+ }
+}
+
+/**
+ * Query the hashtable