diff --git a/README b/README new file mode 100644 index 0000000..f938081 --- /dev/null +++ b/README @@ -0,0 +1 @@ +This is a place holder, please fill in real text when you add stuff. diff --git a/ResValuesModify/jar/ResValuesModify b/ResValuesModify/jar/ResValuesModify index ec75720..818134b 100755 --- a/ResValuesModify/jar/ResValuesModify +++ b/ResValuesModify/jar/ResValuesModify @@ -1,5 +1,13 @@ #!/bin/bash -java -jar $PORT_ROOT/tools/ResValuesModify/jar/ResValuesModify.jar $* +if [ $# -ne 2 -a $# -ne 3 ] +then + echo "usage: ResValuesModify $1 $2 [--app]" + echo " \$1 is the miui values dir" + echo " \$2 is the third-party values dir" + echo " \$3: Merge application's resource, default merge framework-res's resource" +else + java -jar $PORT_ROOT/tools/ResValuesModify/jar/ResValuesModify.jar $* +fi diff --git a/ResValuesModify/jar/ResValuesModify.jar b/ResValuesModify/jar/ResValuesModify.jar index c9dd1b2..528318c 100644 Binary files a/ResValuesModify/jar/ResValuesModify.jar and b/ResValuesModify/jar/ResValuesModify.jar differ diff --git a/ResValuesModify/jar/config b/ResValuesModify/jar/config deleted file mode 100644 index 0fb4585..0000000 --- a/ResValuesModify/jar/config +++ /dev/null @@ -1,18 +0,0 @@ -# NOTE: -# default operation is replace dest node with src node if the dest node exist or -# append src node to the file if dest node doesn't exist -# -# - type [name] -# explicitly declare don't merge this kind of nodes -# -# + type [name] -# explicitly declare that merge this kind of nodes -# -# I array-type [name] -# explicitly declare that to insert new 'items' for 'array' type instead of default replacement -# insert new items to the head of array -# priority of "+" and "I" is higher then "-" - -- add-resource - -I string-array config_statusBarIcons diff --git a/ResValuesModify/src/FileCheck.java b/ResValuesModify/src/FileCheck.java new file mode 100644 index 0000000..97586fb --- /dev/null +++ b/ResValuesModify/src/FileCheck.java @@ -0,0 +1,47 @@ +import java.io.File; +import java.util.ArrayList; + +public class FileCheck { + + public static final String IS_NOT_DIR = " is not folder"; + public static final String IS_NOT_XML = " is not xml file"; + public static final String NO_XML_FILES = " no xml files in this folder"; + public static final String MERGE_FAILED = " merge element failed"; + + public static boolean getXmlFiles(String Path, ArrayList fileArray) { + File dir = new File(Path); + if (true != dir.isDirectory()) { + System.out.println("ERROR: " + Path + IS_NOT_DIR); + return false; + } + + File[] files = dir.listFiles(); + for (File f : files) { + if (true == f.isFile()) { + //if (true == getExtensionName(f.getName()).equals("xml")) { + if(true == f.getName().endsWith(".xml") || true == f.getName().endsWith(".xml.part")){ + fileArray.add(f); + } + } else { + //System.out.println("WARNING" + f.getName() + IS_NOT_XML); + } + } + + if (0 == fileArray.size()) { + System.out.println(Path + NO_XML_FILES); + return false; + } + + return true; + } + + public static String getExtensionName(String filename) { + if ((filename != null) && (filename.length() > 0)) { + int dot = filename.lastIndexOf('.'); + if ((dot > -1) && (dot < (filename.length() - 1))) { + return filename.substring(dot + 1); + } + } + return filename; + } +} diff --git a/ResValuesModify/src/Log.java b/ResValuesModify/src/Log.java deleted file mode 100644 index 052f58a..0000000 --- a/ResValuesModify/src/Log.java +++ /dev/null @@ -1,21 +0,0 @@ -public class Log { - public static void i(String info){ - System.out.println(info); - } - - public static void i(String tag, String info){ - System.out.println( String.format("INFO[%s]: %s", tag, info)); - } - - public static void e(String tag, String err){ - System.err.println( String.format("ERROR[%s]: %s", tag, err)); - } - - public static void w(String tag, String err){ - System.err.println( String.format("WARING[%s]: %s", tag, err)); - } - - public static void e(String err){ - System.err.println(err); - } -} diff --git a/ResValuesModify/src/ResValuesModify.java b/ResValuesModify/src/ResValuesModify.java index f1f7971..43cbdf7 100644 --- a/ResValuesModify/src/ResValuesModify.java +++ b/ResValuesModify/src/ResValuesModify.java @@ -2,78 +2,88 @@ import java.util.ArrayList; public class ResValuesModify { - private ArrayList mSrcFiles = new ArrayList(); - private ArrayList mDestFiles = new ArrayList(); - private ArrayList mConfigFiles = new ArrayList(); - private static final String LOG_TAG = "CHECK"; + private ArrayList mSrcFileArray; + private ArrayList mDestFileArray; + private boolean mIsAppRes = false; public static void main(String[] args) { ResValuesModify resVM = new ResValuesModify(); - if (!resVM.checkArgs(args) || !resVM.checkPath(args)) { - resVM.usage(); + boolean bRet = resVM.parseCommandLine(args); + if (false == bRet) { + return; + } + + bRet = resVM.pathCheck(args); + if (false == bRet) { return; } resVM.mergeXML(); } - private boolean checkArgs(String[] args) { - boolean ret = true; - if (args.length < 2) { - Log.e(LOG_TAG, "invalid argument count"); + public ResValuesModify() { + mSrcFileArray = new ArrayList(); + mDestFileArray = new ArrayList(); + } + + public String delPrefixString(String src, String needDel) { + return null; + } + + private boolean parseCommandLine(String[] args) { + if ((2 != args.length) && (3 != args.length)){ + usage(); return false; } if (args[0].equals(args[1])) { - Log.e(LOG_TAG, "src dir is the same with dest dir"); - ret = false; + System.out.println("ERROR: src dir is the same with dest dir"); + usage(); + return false; } - - for (int i = 2; i < args.length; i++) { - File f = new File(args[i]); - if (f.exists() && f.isFile()) { - mConfigFiles.add(f); - } else { - Log.i(LOG_TAG, "ignore config file:" + f.getName()); - } + + if((3 == args.length) && ("--app".equals(args[2]))){ + mIsAppRes = true; } - return ret; + return true; } - private boolean checkPath(String[] args) { - return perpareXmlFiles(args[0], mSrcFiles) && perpareXmlFiles(args[1], mDestFiles); + private boolean pathCheck(String[] args) { + boolean bRet = FileCheck.getXmlFiles(args[0], mSrcFileArray); + if (false == bRet) { + usage(); + return false; + } + bRet = FileCheck.getXmlFiles(args[1], mDestFileArray); + if (false == bRet) { + usage(); + return false; + } + /* + System.out.println("###################################################"); + System.out.println("*** Source Files: ***********"); + for (int i = 0; i < mSrcFileArray.size(); i++) { + System.out.println("\t" + mSrcFileArray.get(i).getName()); + } + System.out.println("------------------------------------------------"); + System.out.println("*** Destination Files: ******"); + for (int i = 0; i < mDestFileArray.size(); i++) { + System.out.println("\t" + mDestFileArray.get(i).getName()); + } + System.out.println("###################################################"); + */ + + return true; } private void mergeXML() { - (new XMLMerge(mSrcFiles, mDestFiles, mConfigFiles)).merge(); + XMLMerge xmlMerge = new XMLMerge(mSrcFileArray, mDestFileArray, mIsAppRes); + xmlMerge.merge(); } private void usage() { - Log.i("USAGE: "); - Log.i("ResValuesModify src-values-dir dest-values-dir [config-files ...]"); - Log.i(" config-files: config file that explicitly declare merge-rule"); - Log.i(""); - } - - private boolean perpareXmlFiles(String path, ArrayList xmlFiles) { - File dir = new File(path); - if (!dir.isDirectory()) { - Log.w(LOG_TAG, path + " : no such directory"); - return false; - } - - File[] files = dir.listFiles(); - for (File f : files) { - if (f.isFile()) { - if (f.getName().endsWith(".xml") || f.getName().endsWith(".xml.part")) { - xmlFiles.add(f); - } - } - } - - if (0 == xmlFiles.size()) { - Log.w(LOG_TAG, "No xml file in " + path); - return false; - } - return true; + System.out.println("usage: ResValuesModify $1 $2 [--app]"); + System.out.println("\t$1: Miui values dir"); + System.out.println("\t$2: ThirdParty values dir"); + System.out.println("\t$3: Merge application's resource, default merge framework-res's resource"); } } diff --git a/ResValuesModify/src/ResultRecord.java b/ResValuesModify/src/ResultRecord.java new file mode 100644 index 0000000..0948c44 --- /dev/null +++ b/ResValuesModify/src/ResultRecord.java @@ -0,0 +1,34 @@ +import java.util.ArrayList; + +public class ResultRecord { + + private static ResultRecord mResultInstance = null; + + public static final String IS_NOT_DIR = " :is not folder"; + public static final String IS_NOT_XML = " :is not xml file"; + public static final String NO_XML_FILES = " : no xml files in this folder"; + public static final String MERGE_FAILED = " : merge element failed"; + + private ArrayList mResult; + + private ResultRecord() { + mResult = new ArrayList(); + } + + public static ResultRecord create(){ + if(null == mResultInstance){ + mResultInstance = new ResultRecord(); + } + return mResultInstance; + } + + public void addRecord(String s) { + mResult.add(s); + } + + public void printResult(){ + for(int i = 0; i < mResult.size(); i ++){ + System.out.println(mResult.get(i)); + } + } +} diff --git a/ResValuesModify/src/XMLMerge.java b/ResValuesModify/src/XMLMerge.java index 5d5dae9..7931e64 100644 --- a/ResValuesModify/src/XMLMerge.java +++ b/ResValuesModify/src/XMLMerge.java @@ -1,432 +1,396 @@ -import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; import java.io.FileWriter; -import java.io.IOException; import java.io.Writer; import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; -import org.w3c.dom.Text; import com.sun.org.apache.xml.internal.serialize.OutputFormat; import com.sun.org.apache.xml.internal.serialize.XMLSerializer; +import java.util.regex.Pattern; +import java.util.regex.Matcher; + public class XMLMerge { - private static Map sSrc = new HashMap(); - private static Map sDes = new HashMap(); - private static Map> sIncludeRule = new HashMap>(); - private static Map> sExcludeRule = new HashMap>(); - private static Map> sInsertRule = new HashMap>(); - - private static final int MERGE_DONT_NEED_MERGE = 1; - private static final int MERGE_DONT_FIND_DEST_FILE = 2; - private static final int MERGE_ADD_ELEMENT = 3; - private static final int MERGE_MODIFY_ELEMENT = 4; - private static final int MERGE_INCERT_ITEMS = 5; - private static final int MERGE_INVALID_NODE = 6; - private static final String RESOURCES_TAG = "resources"; - private static final String STRING_ARRAY_TAG = "string-array"; - private static final String STRING_TAG = "string"; - private static final String XLIFF_TAG = "xliff:g"; - private static final String ITEM_TAG = "item"; - private static final String NAME_TAG = "name"; - private static final String LOG_TAG = "merge xml"; - private static final String MSGID_TAG = "msgid"; - - public XMLMerge(ArrayList srcFiles, ArrayList desFiles, ArrayList configFiles) { - for (File srcFile : srcFiles) { - try { - sSrc.put(srcFile, - DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(srcFile)); - } catch (Exception e) { - e.printStackTrace(); - Log.w(LOG_TAG, "src file:" + srcFile.getName() + " is invalid xml file"); - } - } + private ArrayList mSrcFiles; + private ArrayList mDestFiles; + private boolean mIsAppRes = false; + + public static final int MERGE_MATCH_ALL = 0; + public static final int MERGE_DONT_NEED_MERGE = 1; + public static final int MERGE_DONT_FIND_DEST_FILE = 2; + public static final int MERGE_EXCEPTION = 3; + public static final int MERGE_ADD_ELEMENT = 4; + public static final int MERGE_MODIFY_ELEMENT = 5; + public static final int MERGE_FAILED = 6; + + public XMLMerge(ArrayList srcFiles, ArrayList destFiles, boolean isAppRes) { + mSrcFiles = srcFiles; + mDestFiles = destFiles; + mIsAppRes = isAppRes; + } - for (File desFile : desFiles) { - try { - sDes.put(desFile, - DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(desFile)); - } catch (Exception e) { - e.printStackTrace(); - Log.w(LOG_TAG, "dest file:" + desFile.getName() + " is invalid xml file"); - } + public void merge() { + for (int i = 0; i < mSrcFiles.size(); i++) { + mergeFile(mSrcFiles.get(i)); } - - parseConfigFile(configFiles); - printConfig(); } - private void parseConfigFile(ArrayList configFiles) { - for (File f : configFiles) { - String l; - BufferedReader r = null; - try { - r = new BufferedReader(new FileReader(f)); - while ((l = r.readLine()) != null) { - l = l.trim(); - if (l.length() == 0 || l.startsWith("#")) { - continue; - } - String[] item = l.split(" "); - if (item.length > 1 - && ("-".equals(item[0]) || "+".equals(item[0]) || "I" - .equalsIgnoreCase(item[0]))) { - String nodeName = item[1]; - HashSet nameAttrs; - if ("-".equals(item[0])) { - nameAttrs = sExcludeRule.get(nodeName); - if (nameAttrs == null) { - nameAttrs = new HashSet(); - sExcludeRule.put(nodeName, nameAttrs); - } - } else if ("+".equals(item[0])) { - nameAttrs = sIncludeRule.get(nodeName); - if (nameAttrs == null) { - nameAttrs = new HashSet(); - sIncludeRule.put(nodeName, nameAttrs); - } - } else { - nameAttrs = sInsertRule.get(nodeName); - if (nameAttrs == null) { - nameAttrs = new HashSet(); - sInsertRule.put(nodeName, nameAttrs); - } - } - if (item.length == 2) { - nameAttrs.add("*"); - } else { - String nameAttrValue = item[2]; - nameAttrs.add(nameAttrValue); - } - } - } - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } finally { - if (r != null) { - try { - r.close(); - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } + private void mergeFile(File file) { + try { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(file); + Element root = adjustMergeRoot(doc); + if (null == root) { + System.out.println("DON'T MERGE: " + file.getCanonicalPath()); + return; } + + //System.out.println("***************START MERGE***********"); + //System.out.println("SRC XML FILE: " + file.getName()); + + traverseMergeXML(root, file); + //System.out.println("---------------END MERGE-----------"); + //System.out.println(); + //System.out.println(); + + } catch (Exception e) { + e.printStackTrace(); } + return; } - private void printConfig() { - Log.i("------------------------------------------------"); - Log.i(LOG_TAG, "Include:"); - for (Map.Entry> e : sIncludeRule.entrySet()) { - Log.i(LOG_TAG, "-->" + e.getKey()); - for (String s : e.getValue()) { - Log.i(LOG_TAG, "----->" + s); - } - } - Log.i(""); - Log.i(LOG_TAG, "Exclude:"); - for (Map.Entry> e : sExcludeRule.entrySet()) { - Log.i(LOG_TAG, "-->" + e.getKey()); - for (String s : e.getValue()) { - Log.i(LOG_TAG, "----->" + s); - } - } - Log.i(""); - Log.i(LOG_TAG, "Insert:"); - for (Map.Entry> e : sInsertRule.entrySet()) { - Log.i(LOG_TAG, "-->" + e.getKey()); - for (String s : e.getValue()) { - Log.i(LOG_TAG, "----->" + s); - } + private Element adjustMergeRoot(Document doc) { + Element root = doc.getDocumentElement(); + if (true == hasNode("/resources/string-array", doc)) { + // System.out.println("Node find :xmlns:xliff"); + root = adjustStringArrayMergeRoot(doc); + } else if (true == hasNode("/resources/add-resource", doc)) { + // System.out.println("IS ADD RESOURCES"); + root = adjustAddResources(doc); + } else if (true == hasNode("/resources/style", doc)) { + root = adjustStyleRoot(doc); + } else { } - Log.i(""); - Log.i("------------------------------------------------"); + return root; } - private boolean chcekFile() { - for (Map.Entry src : sSrc.entrySet()) { - if (src.getValue().getElementsByTagName(RESOURCES_TAG).getLength() != 1) { - Log.w(LOG_TAG, "src file:" + src.getKey().getName() + " don't include a valid \"" - + RESOURCES_TAG + "\" node"); - sSrc.remove(src.getKey()); + private Element adjustStringArrayMergeRoot(Document doc) { + NodeList nList = doc.getElementsByTagName("resources"); + Element root = (Element) nList.item(0); + root.removeAttribute("xmlns:xliff"); + + nList = root.getElementsByTagName("xliff:g"); + if (nList.getLength() > 0){ + Node papa = nList.item(0).getParentNode().getParentNode(); + ArrayList vals = new ArrayList(); + while (root.getElementsByTagName("xliff:g").getLength() != 0) { + vals.add(nList.item(0).getTextContent()); + nList.item(0).getParentNode().getParentNode().removeChild(nList.item(0).getParentNode()); } - } - for (Map.Entry des : sDes.entrySet()) { - if (des.getValue().getElementsByTagName(RESOURCES_TAG).getLength() != 1) { - Log.w(LOG_TAG, "dest file:" + des.getKey().getName() + " don't include a valid \"" - + RESOURCES_TAG + "\" node"); - sDes.remove(des.getKey()); + for (int i = 0; i < vals.size(); i++) { + Element e = doc.createElement("item"); + e.appendChild(doc.createTextNode(vals.get(i))); + papa.appendChild(e); } + return (Element)papa; } - - if (sSrc.isEmpty()) { - Log.w(LOG_TAG, "no vaild src files"); - return false; - } - - if (sDes.isEmpty()) { - Log.w(LOG_TAG, "no valid dest files"); - return false; - } - return true; + //return root + //TODO + //frameworks/miui/overlay/frameworks/base/core/res/res/values/arrays.xml should not be merged + return null; } - public void merge() { - if (!chcekFile()) { - return; - } - - for (Map.Entry entry : sSrc.entrySet()) { - Log.i("------------------------------------------------"); - Log.i(LOG_TAG, "merge file: " + entry.getKey().getName()); - mergeFile(entry); - Log.i("------------------------------------------------"); - Log.i(""); - } + private Element adjustStyleRoot(Document doc) { - saveDestFile(); + return doc.getDocumentElement(); } - private void saveDestFile() { - for (Map.Entry des : sDes.entrySet()) { - writeXML(des.getValue(), des.getKey()); - } - } + private Element adjustAddResources(Document doc) { - private void mergeFile(Map.Entry entry) { - Document doc = entry.getValue(); - formatDoc(doc); - Node resNode = doc.getElementsByTagName(RESOURCES_TAG).item(0); - NodeList subTypes = resNode.getChildNodes(); - for (int i = 0; i < subTypes.getLength(); i++) { - if (Node.ELEMENT_NODE == subTypes.item(i).getNodeType()) { - mergeNode(subTypes.item(i)); - } - } - return; + return doc.getDocumentElement(); } private int mergeNode(Node node) { - if (!checkNode(node)) { - Log.i(LOG_TAG, "invalid src node: " + node.getNodeName()); - return MERGE_INVALID_NODE; - } + String xpathStr = getXpathStr(node); + String textContent = node.getTextContent(); + //System.out.println(); + //System.out.println(xpathStr + ":" + node.getTextContent()); - if (!needMerge(node)) { - Log.i(LOG_TAG, "dont need merge src node: " + node.getNodeName() + "[" + "name=" - + ((Element) node).getAttribute(NAME_TAG) + "]"); + if (xpathStr.contains("/resources/add-resource")) { + //System.out.println("DONT NEED TO ADD ELEMENT: add-resource"); return MERGE_DONT_NEED_MERGE; } - if (tryInsertItemsToDesArrayNode(node)) { - Log.i(LOG_TAG, "inscert new items to dest array node: " + node.getNodeName() + "[" - + "name=" - + ((Element) node).getAttribute(NAME_TAG) + "]"); - return MERGE_INCERT_ITEMS; + File destFile = getDestFile(xpathStr); + if (null == destFile) { + //System.out.println("DEST FILE: DONT FOUND"); + return MERGE_DONT_FIND_DEST_FILE; } - if (tryReplaceDesNode(node)) { - Log.i(LOG_TAG, "replace node to dest: " + node.getNodeName() + "[" + "name=" - + ((Element) node).getAttribute(NAME_TAG) + "]"); - return MERGE_MODIFY_ELEMENT; - } - - if (tryAddDesNode(node)) { - Log.i(LOG_TAG, "add node to dest: " + node.getNodeName() + "[" + "name=" - + ((Element) node).getAttribute(NAME_TAG) + "]"); - return MERGE_ADD_ELEMENT; - } - Log.i(LOG_TAG, "can't find dest file for node: " + node.getNodeName() + "[" + "name=" - + ((Element) node).getAttribute(NAME_TAG) + "]"); - return MERGE_DONT_FIND_DEST_FILE; - } - - private void formatDoc(Document doc) { - removeXliffgNode(doc); - removeMsgidAttr(doc); - } - - private boolean checkNode(Node node) { - // check if node has a "name" attribute - return !"".equals(((Element) node).getAttribute(NAME_TAG)); - } + //System.out.println("DEST FILE --> " + destFile.getName()); - private boolean needMerge(Node node) { - // search Include and Insert config firstly - if (matchConfig(node, sIncludeRule) || matchConfig(node, sInsertRule)) { - return true; - } - // search Exclude config secondly - return !matchConfig(node, sExcludeRule); + return mergeNodeToDestFile(xpathStr, textContent, destFile); } - private boolean matchConfig(Node node, Map> configs) { - HashSet nameAttrValues; - if ((nameAttrValues = configs.get(node.getNodeName())) == null) { - return false; - } - if (nameAttrValues.contains("*") - || nameAttrValues.contains(((Element) node).getAttribute(NAME_TAG))) { - return true; - } - return false; - } - - // try insert the new items to array node - private boolean tryInsertItemsToDesArrayNode(Node node) { - String nodeName = node.getNodeName(); - String nameAttrValue = ((Element) node).getAttribute(NAME_TAG); - if (matchConfig(node, sInsertRule)) { - for (Map.Entry des : sDes.entrySet()) { - Document desDoc = des.getValue(); - NodeList desNodes = desDoc.getElementsByTagName(nodeName); - for (int i = 0; i < desNodes.getLength(); i++) { - Node desNode = desNodes.item(i); - try { - if (nameAttrValue.equals(((Element) desNode).getAttribute(NAME_TAG))) { - NodeList desItems = ((Element) desNode).getElementsByTagName(ITEM_TAG); - NodeList srcItems = ((Element) node).getElementsByTagName(ITEM_TAG); - if (desItems.getLength() == 0 || srcItems.getLength() == 0) { - return false; - } - ArrayList desItemTexts = new ArrayList(); - for (int j = 0; j < desItems.getLength(); j++) { - desItemTexts.add(desItems.item(j).getTextContent()); + private int mergeNodeToDestFile(String xpathStr, String textContent, File destFile) { + String tryMatchStr = new String(xpathStr); + try { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(destFile); + doc.getDocumentElement().normalize(); + + String rootName = doc.getDocumentElement().getNodeName(); + //matching until trymatchStr back to root or tryMatchStr is null + while (null != tryMatchStr && false == tryMatchStr.equals("/" + rootName)) { + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + XPathExpression expr = xpath.compile(tryMatchStr); + NodeList nList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); + + if (null != nList && 0 != nList.getLength()) { //find a match, merge node to file + String lostMatchStr = new String(xpathStr); + //System.out.println(getLineNumberString(new Exception()) + "Match: " + tryMatchStr); + + if (true == xpathStr.equals(tryMatchStr)) { //if absXpathStr is found in xml fine, write it into file directly + String subStr = tryMatchStr.substring(tryMatchStr.lastIndexOf('/') + 1); + if (true == subStr.contains("[@")) { //if the element contain Attribute, just need to modify the element's textcontent + if(nList.item(0).getTextContent().equals(textContent)){ + //System.out.println(getLineNumberString(new Exception()) + "ALL MATCH"); + return MERGE_MATCH_ALL; + }else{ + //System.out.println(getLineNumberString(new Exception()) + "MODIFY TEXTCONTENT: " + // + nList.item(0).getTextContent() + " -> " + textContent); + nList.item(0).setTextContent(textContent); + writeXML(doc, destFile); + return MERGE_MODIFY_ELEMENT; } - - for (int j = 0; j < srcItems.getLength(); j++) { - String srcText = srcItems.item(j).getTextContent(); - if (!desItemTexts.contains(srcText)) { - Element item = desDoc.createElement(ITEM_TAG); - item.appendChild(desDoc.createTextNode(srcText)); - desNode.insertBefore(item, desItems.item(0)); + } else { //element don't contain attriute, check if or not exist element with same textcontent + Node papa = nList.item(0).getParentNode(); + String nodeName = nList.item(0).getNodeName(); + for (int i = 0; i < nList.getLength(); i++) { + if (nList.item(i).getTextContent().equals(textContent)) { + //System.out.println(getLineNumberString(new Exception()) + "ALL MATCH"); + return MERGE_MATCH_ALL; } } - return true; + Element e = doc.createElement(nodeName); + papa.appendChild(e); + e.setTextContent(textContent); + writeXML(doc, destFile); + //System.out.println(getLineNumberString(new Exception()) + "ADD ELEMENT: " + getXpathStr(e) + ":" + textContent); + return MERGE_ADD_ELEMENT; } - } catch (Exception e) { - e.printStackTrace(); - return false; + } else { + lostMatchStr = lostMatchStr.replace(tryMatchStr, ""); + } + + // System.out.println(getLineNumberString(new Exception()) + + // "LostMatch: " + lostMatchStr); + + //match a part of absXpathStr + if (true == lostMatchStr.startsWith("/")) { + return addNode(doc, (Element) (nList.item(0)), destFile, lostMatchStr, textContent); + } else if (true == lostMatchStr.startsWith("[@")){ + String attrName = lostMatchStr.substring(lostMatchStr.indexOf('@') + 1, lostMatchStr.indexOf('=')); + lostMatchStr = lostMatchStr.replaceFirst("\'", ""); + String attrContent = lostMatchStr.substring(lostMatchStr.indexOf('=') + 1, lostMatchStr.indexOf('\'')); + String nodeName = nList.item(0).getNodeName(); + Element e = doc.createElement(nodeName); + e.setAttribute(attrName, attrContent); + nList.item(0).getParentNode().appendChild(e); + if (lostMatchStr.indexOf('/') < 0) { + e.appendChild(doc.createTextNode(textContent)); + writeXML(doc, destFile); + //System.out.println(getLineNumberString(new Exception()) + "ADD ELEMENT: " + getXpathStr(e) + ":" + textContent); + return MERGE_ADD_ELEMENT; + } else { + return addNode(doc, e, destFile, lostMatchStr.substring(lostMatchStr.indexOf('/')), textContent); + } + }else{ + //System.out.println(getLineNumberString(new Exception()) + "INVAILD ELEMENT"); } } + tryMatchStr = getUpperXpathStr(tryMatchStr); + // System.out.println(getLineNumberString(new Exception()) + + // "TryMatch: " + tryMatchStr); } + } catch (Exception e) { + e.printStackTrace(); + return MERGE_EXCEPTION; } - return false; + return MERGE_FAILED; } - // if dest node with same node name and "name" attribute - // just to replace the dest node with src node - private boolean tryReplaceDesNode(Node node) { - String nodeName = node.getNodeName(); - String nameAttrValue = ((Element) node).getAttribute(NAME_TAG); - for (Map.Entry des : sDes.entrySet()) { - Document desDoc = des.getValue(); - NodeList desNodes = des.getValue().getElementsByTagName(nodeName); - for (int i = 0; i < desNodes.getLength(); i++) { - Node desNode = desNodes.item(i); - try { - if (nameAttrValue.equals(((Element) desNode).getAttribute(NAME_TAG))) { - desNode.getParentNode().replaceChild(desDoc.importNode(node, true), - desNode); - return true; - } - } catch (Exception e) { - e.printStackTrace(); - return false; + private int addNode(Document doc, Element element, File destFile, String xpathStr, String textContent) { + String tmp = new String(xpathStr); + while (tmp.indexOf('/') > -1) { //do until there is no element + tmp = tmp.replaceFirst("/", ""); + if (tmp.indexOf('/') > -1) { //this is not the last element + String subTmp = tmp.substring(0, tmp.indexOf('/')); + if (subTmp.contains("[@")) { //element contains a Attributes + String nodeName = new String(subTmp.substring(0, subTmp.indexOf('['))); + String attrName = new String(subTmp.substring(subTmp.indexOf('@') + 1, subTmp.indexOf('='))); + String attrContent = new String(subTmp.substring(subTmp.indexOf('\'') + 1, subTmp.lastIndexOf('\''))); + + Element subElement = doc.createElement(nodeName); + subElement.setAttribute(attrName, attrContent); + element.appendChild(subElement); + element = subElement; + } else { + String nodeName = new String(subTmp); + Element subElement = doc.createElement(nodeName); + element = subElement; + } + tmp = tmp.substring(tmp.indexOf('/')); + } else { + String subTmp = tmp; + if (subTmp.contains("[@")) { //element contains a Attributes + String nodeName = new String(subTmp.substring(0, subTmp.indexOf('['))); + String attrName = new String(subTmp.substring(subTmp.indexOf('@') + 1, subTmp.indexOf('='))); + String attrContent = new String(subTmp.substring(subTmp.indexOf('\'') + 1, subTmp.lastIndexOf('\''))); + + Element subElement = doc.createElement(nodeName); + subElement.setAttribute(attrName, attrContent); + element.appendChild(subElement); + element = subElement; + } else { + String nodeName = new String(subTmp); + + Element subElement = doc.createElement(nodeName); + element = subElement; } + element.appendChild(doc.createTextNode(textContent)); + writeXML(doc, destFile); + //System.out.println(getLineNumberString(new Exception()) + "ADD ELEMENT: " + getXpathStr(element) + ":" + textContent); + return MERGE_ADD_ELEMENT; } } - return false; + return MERGE_FAILED; } - // add node to the doc which include same node name - private boolean tryAddDesNode(Node node) { - String nodeName = node.getNodeName(); - for (Map.Entry des : sDes.entrySet()) { - Document desDoc = des.getValue(); - if (existNode(des.getValue(), nodeName)) { - try { - desDoc.getElementsByTagName(nodeName).item(0).getParentNode() - .appendChild(desDoc.importNode(node, true)); - return true; - } catch (Exception e) { - e.printStackTrace(); - return false; + private File getDestFile(String xpathStr) { + if (null == xpathStr) { + return null; + } + try { + while (null != xpathStr && false == xpathStr.equals("/resources")) { + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + XPathExpression expr = xpath.compile(xpathStr); + for (int i = 0; i < mDestFiles.size(); i++) { + DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); + DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); + Document doc = dBuilder.parse(mDestFiles.get(i)); + doc.getDocumentElement().normalize(); + NodeList nList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); + if (null != nList && 0 != nList.getLength()) { + return mDestFiles.get(i); + } } + xpathStr = getUpperXpathStr(xpathStr); } + } catch (Exception e) { + e.printStackTrace(); } - return false; + return null; } - private boolean existNode(Document doc, String nodeName) { - NodeList nodes = doc.getElementsByTagName(nodeName); - return nodes.getLength() > 0; - } + private String getUpperXpathStr(String xpathStr) { + if ((xpathStr != null) && (xpathStr.length() > 0)) { + int pos1 = xpathStr.lastIndexOf(']'); + int pos2 = xpathStr.lastIndexOf('['); + int pos3 = xpathStr.lastIndexOf('/'); + if (pos1 > -1 && pos2 > -1 && pos3 > -1 && pos1 > pos2 && pos2 > pos3) { + return xpathStr.substring(0, pos2); + } else if (pos3 > pos1) { + return xpathStr.substring(0, pos3); + } else { - private void removeXliffgNodeFromStringArray(Document doc) { - NodeList stringArrays = doc.getElementsByTagName(STRING_ARRAY_TAG); - for (int i = 0; i < stringArrays.getLength(); i++) { - Element stringArray = (Element) stringArrays.item(i); - NodeList xliffs = stringArray.getElementsByTagName(XLIFF_TAG); - if (xliffs.getLength() > 0) { - Node papa = xliffs.item(0).getParentNode().getParentNode(); - ArrayList vals = new ArrayList(); - while (stringArray.getElementsByTagName(XLIFF_TAG).getLength() != 0) { - vals.add(xliffs.item(0).getTextContent()); - xliffs.item(0).getParentNode().getParentNode() - .removeChild(xliffs.item(0).getParentNode()); - } - for (int j = 0; j < vals.size(); j++) { - Element e = doc.createElement(ITEM_TAG); - e.appendChild(doc.createTextNode(vals.get(j))); - papa.appendChild(e); - } } } + return null; } - private void removeXliffgNodeFromString(Document doc) { - Element res = (Element) doc.getElementsByTagName(RESOURCES_TAG).item(0); - NodeList xliffs = res.getElementsByTagName(XLIFF_TAG); - int len = xliffs.getLength(); - while (len > 0) { - Node xliff = xliffs.item(0); - Text text = doc.createTextNode(xliff.getTextContent()); - xliff.getParentNode().replaceChild(text, xliff); - - xliffs = res.getElementsByTagName(XLIFF_TAG); - len = xliffs.getLength(); + private boolean hasNode(String xpathStr, Document doc) { + try { + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + XPathExpression expr = xpath.compile(xpathStr); + + NodeList nList = (NodeList) expr.evaluate(doc, XPathConstants.NODESET); + if (null != nList && 0 != nList.getLength()) { + return true; + } + } catch (Exception e) { + e.printStackTrace(); } + return false; } - private void removeXliffgNode(Document doc) { - removeXliffgNodeFromStringArray(doc); - removeXliffgNodeFromString(doc); + public void traverseMergeXML(Node node, File file) { + if (true == isElementLeaf(node)) { + switch(mergeNode(node)){ + case MERGE_ADD_ELEMENT: + case MERGE_MODIFY_ELEMENT: + case MERGE_DONT_NEED_MERGE: + break; + + case MERGE_DONT_FIND_DEST_FILE: + System.out.println(" " + "{" + file.getName() + "}" + " DONT FIND DEST FILE: " + getXpathStr(node)); + break; + + case MERGE_FAILED: + case MERGE_EXCEPTION: + System.out.println(" " + "{" + file.getName() + "}" + " MERGE FAILED: " + getXpathStr(node)); + break; + + default: + break; + } + } + // Now traverse the rest of the tree in depth-first order. + if (node.hasChildNodes()) { + NodeList nList = node.getChildNodes(); + int size = nList.getLength(); + for (int i = 0; i < size; i++) { + // Recursively traverse each of the children. + traverseMergeXML(nList.item(i), file); + } + } } - private void removeMsgidAttr(Document doc) { - Node resNode = doc.getElementsByTagName(RESOURCES_TAG).item(0); - NodeList nodes = resNode.getChildNodes(); - for (int i = 0; i < nodes.getLength(); i++) { - Node node = nodes.item(i); - if (Node.ELEMENT_NODE == node.getNodeType()) { - ((Element) node).removeAttribute(MSGID_TAG); + private boolean isElementLeaf(Node node) { + if (null == node) { + return false; + } + + if (Node.ELEMENT_NODE == node.getNodeType()) { + if (true == node.hasChildNodes()) { + NodeList sonList = node.getChildNodes(); + for (int i = 0; i < sonList.getLength(); i++) { + if (Node.ELEMENT_NODE == sonList.item(i).getNodeType()) { + return false; + } + } } + return true; + } else { + return false; } } @@ -438,9 +402,63 @@ private void writeXML(Document doc, File file) { Writer output = new BufferedWriter(new FileWriter(file)); XMLSerializer serializer = new XMLSerializer(output, format); serializer.serialize(doc); - } catch (Exception e) { + // System.out.println("Write Xml File"); + + }catch (Exception e) { e.printStackTrace(); - Log.e(LOG_TAG, "write xml file " + file.getName() + " failed"); } } + + public String getXpathStr(Node node) { + String xpathStr = ""; + while (null != node) { + if (true == node.hasAttributes()) { + xpathStr = "/" + node.getNodeName() + "[@" + node.getAttributes().item(0).getNodeName() + + "='" + node.getAttributes().item(0).getNodeValue() + "']" + xpathStr; + + } else { + xpathStr = "/" + node.getNodeName() + xpathStr; + } + + node = node.getParentNode(); + } + xpathStr = "/" + xpathStr; + //System.out.println("pre: " + xpathStr); + + ArrayList subStrArray = new ArrayList(); + subStrArray.add("//#document"); + if(!mIsAppRes){ + subStrArray.add("android:"); + } + xpathStr = delSubString(xpathStr, subStrArray); + + //System.out.println("post:" + xpathStr); + return xpathStr; + } + + public String delSubString(String str, ArrayList subStrArray) { + for (int i = 0; i < subStrArray.size(); i++) { + if (str.contains(subStrArray.get(i))) { + str = str.replace(subStrArray.get(i), ""); + } + } + return str; + } + + public static String getLineNumberString(Exception e) { + StackTraceElement[] trace = e.getStackTrace(); + if (trace == null || trace.length == 0) { + return "ERROR: -1"; + } + // return new String("LINE" + String.format("%d", trace[0].getLineNumber()) + "--> "); + return new String(""); + } + + public static int getLineNumber(Exception e) { + StackTraceElement[] trace = e.getStackTrace(); + if (trace == null || trace.length == 0) { + return -1; + } + return trace[0].getLineNumber(); + } } diff --git a/aapt b/aapt new file mode 100755 index 0000000..bd346af Binary files /dev/null and b/aapt differ diff --git a/aapt.exe b/aapt.exe index 54718d6..e4e05e0 100755 Binary files a/aapt.exe and b/aapt.exe differ diff --git a/add_miui_methods_and_variables.sh b/add_miui_methods_and_variables.sh deleted file mode 100755 index 341e45c..0000000 --- a/add_miui_methods_and_variables.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash -# -# Copyright 2016 Miui Patchrom -# - -BASE_DIR=$1 -MOD_DIR=$2 -TARGET_DIR=$3 - -IFS=$'\x0A' - -tmp_fifo_file="/tmp/$$.fifo" -mkfifo $tmp_fifo_file -exec 9<>$tmp_fifo_file - -# 8 threads -for((i=0;i<8;i++)) -do - echo "" -done >&9 - - -for modSmaliFile in $(find $MOD_DIR -name "*.smali" ! -name "*\$[0-9]*.smali" ! -name "R\$*.smali") -do - baseSmaliFile=${modSmaliFile/$MOD_DIR/$BASE_DIR} - targetSmaliFile=${modSmaliFile/$MOD_DIR/$TARGET_DIR} - read -u9 - { - if [ -f $baseSmaliFile ];then - if [ "$(diff $baseSmaliFile $modSmaliFile)" == "" ];then - echo "" >&9 - continue - fi - methodBeginLines=($(grep -n "^.method " $modSmaliFile)) - methodEndLines=($(grep -n "^.end method" $modSmaliFile)) - for((i=0;i<${#methodBeginLines[@]};i++)) - do - if [ "$(echo ${methodBeginLines[$i]} | grep -E 'static synthetic|clinit')" == "" ];then - grepPattern="[^->]$(echo ${methodBeginLines[$i]##* } | sed 's/\[/\\\[/g')" - if [ "$(grep $grepPattern $baseSmaliFile)" == "" ];then - beginLineNum=$(echo ${methodBeginLines[$i]} | cut -d ':' -f1) - endLineNum=$(echo ${methodEndLines[$i]} | cut -d ':' -f1) - echo "Add method ${methodBeginLines[$i]##* } into $targetSmaliFile" - sed -n ${beginLineNum},${endLineNum}p $modSmaliFile >> $targetSmaliFile - fi - fi - done - - fieldLines=($(grep -En "^.field |^.end field" $modSmaliFile)) - linesCount=${#fieldLines[@]} - for ((i=0;i<$linesCount;i++)) - do - beginLine=${fieldLines[$i]%% =*} - grepPattern="[^->]$(echo ${beginLine##* } | sed 's/\[/\\\[/g')" - if [ "$(grep $grepPattern $baseSmaliFile)" == "" ];then - echo "Add field ${beginLine##* } into $targetSmaliFile" - beginLineNum=$(echo $beginLine | cut -d ":" -f1) - if [ $(($linesCount-$i)) -ne 1 -a "$(echo ${fieldLines[$i+1]} | grep ".end field")" != "" ];then - endLineNum=$(echo ${fieldLines[$i+1]} | cut -d ":" -f1) - sed -n ${beginLineNum},${endLineNum}p $modSmaliFile >> $targetSmaliFile - i=$(($i+1)) - else - sed -n ${beginLineNum}p $modSmaliFile >> $targetSmaliFile - fi - fi - done - fi - echo "" >&9 - }& -done -wait -exec 9>&- - -exit 0 diff --git a/add_miui_smail.sh b/add_miui_smail.sh index 2e4cc54..9b2e751 100755 --- a/add_miui_smail.sh +++ b/add_miui_smail.sh @@ -1,49 +1,19 @@ #!/bin/bash # -# Add miui smali files +# $1: dir for miui +# $2: dir for original # -# $1: android original src dir -# $2: miui src dir -# $3: target src dir - -BASE_DIR=$1 -MIUI_DIR=$2 -TARGET_DIR=$3 -OVERLAY_DIR=$PORT_ROOT/android/overlay -OVERLAY_CLASSES=$OVERLAY_DIR/OVERLAY_CLASSES - -$PORT_ROOT/tools/add_miui_methods_and_variables.sh $BASE_DIR $MIUI_DIR $TARGET_DIR - - -for class in `cat $OVERLAY_CLASSES | grep -Ev "^$|^#.*$"` -do - target_smali=$TARGET_DIR/smali/$class.smali - target_classes=$TARGET_DIR/smali/$class* - if [ -f "$target_smali" ];then - rm -f $target_classes - fi -done - - -for overlay_smali in `find $OVERLAY_DIR -name "*.smali" | sed 's/\$.*/.smali/' | uniq` -do - target_smali=${overlay_smali/$OVERLAY_DIR/$TARGET_DIR} - if [ -f "$target_smali" ];then - cp -f ${overlay_smali/.smali/}*.smali `dirname $target_smali` - fi -done - - -for file in `find $MIUI_DIR -name "*.smali"` +for file in `find $1 -name "*.smali"` do - newfile=${file/$MIUI_DIR/$TARGET_DIR} + newfile=${file/$1/$2} if [ ! -f "$newfile" ] then mkdir -p `dirname $newfile` + echo "add smali from miui: $file" cp $file $newfile fi done if [ -f "customize_framework.sh" ]; then - bash ./customize_framework.sh $2 $3 + ./customize_framework.sh $1 $2 fi diff --git a/apkcerts.py b/apkcerts.py index 62f5c6f..3f72c72 100755 --- a/apkcerts.py +++ b/apkcerts.py @@ -1,23 +1,16 @@ #!/usr/bin/env python -import os import sys import string import xml import xml.dom from xml.dom import minidom -def getName(pkg, updatedPackages): - codePath = pkg.attributes["codePath"].value - if codePath.startswith("/data/app"): - codePath = "" - pkgName = pkg.attributes["name"].value - for updatedPkg in updatedPackages: - updatedPkgName = updatedPkg.attributes["name"].value - if updatedPkgName == pkgName: - codePath=updatedPkg.attributes["codePath"].value - break - return os.path.basename(codePath) +def getName(codePath): + if codePath.startswith("/system/app"): + return codePath.replace("/system/app/", "") + else : + return "" def usage(): print "Usage: python ./apkcerts.py path-to-packages.xml path-to-apkcerts.txt" @@ -33,11 +26,10 @@ def main(): print "Error: %s doesn't exist or isn't a vaild xml file" %(sys.argv[1]) sys.exit(1) - updatedPackages = xmldoc.getElementsByTagName("updated-package") packages = xmldoc.getElementsByTagName("package") sigpkgs = {} for pkg in packages: - name = getName(pkg, updatedPackages) + name = getName(pkg.attributes["codePath"].value) cert= pkg.getElementsByTagName("cert") if not cert or not name: continue index = cert[0].getAttribute("index") @@ -62,9 +54,9 @@ def main(): sig = sigmap.get(keyindex, None) for pkgname in pkgnames: if sig: - line = 'name="{0}.apk" certificate="build/target/product/security/{1}.x509.pem" private_key="build/target/product/security/{1}.pk8"\n'.format(pkgname, sig) + line = 'name="{0}" certificate="build/target/product/security/{1}.x509.pem" private_key="build/target/product/security/{1}.pk8"\n'.format(pkgname, sig) else: - line = 'name="{0}.apk" certificate="PRESIGNED" private_key=""\n'.format(pkgname) + line = 'name="{0}" certificate="PRESIGNED" private_key=""\n'.format(pkgname) f.write(line) if "__main__" == __name__: diff --git a/apktool b/apktool index 0c887be..b439eff 100755 --- a/apktool +++ b/apktool @@ -56,7 +56,7 @@ javaOpts="" # line and adjust the value accordingly. Use "java -X" for a list of options # you can pass here. # -javaOpts="-Xmx1024M" +javaOpts="-Xmx256M" # Alternatively, this will extract any parameter "-Jxxx" from the command line # and pass them to Java (instead of to dx). This makes it possible for you to diff --git a/apktool.jar b/apktool.jar index 58dd293..e7d68a8 100644 Binary files a/apktool.jar and b/apktool.jar differ diff --git a/baksmali b/baksmali index bd3f820..31f782f 100755 --- a/baksmali +++ b/baksmali @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# As per the Apache license requirements, this file has been modified -# from its original state. -# -# Such modifications are Copyright (C) 2010 Ben Gruver, and are released -# under the original license - # This script is a wrapper around baksmali.jar, so you can simply call # "baksmali", instead of java -jar baksmali.jar. It is heavily based on # the "dx" script from the Android SDK @@ -61,7 +55,7 @@ javaOpts="" # If you want DX to have more memory when executing, uncomment the following # line and adjust the value accordingly. Use "java -X" for a list of options # you can pass here. -# +# javaOpts="-Xmx256M" # Alternatively, this will extract any parameter "-Jxxx" from the command line diff --git a/baksmali.jar b/baksmali.jar index 2ff1ae3..d2ba043 100644 Binary files a/baksmali.jar and b/baksmali.jar differ diff --git a/build_target_files.sh b/build_target_files.sh index 4106282..099fc96 100755 --- a/build_target_files.sh +++ b/build_target_files.sh @@ -10,16 +10,6 @@ OTA_FROM_TARGET_FILES=$TOOL_DIR/releasetools/ota_from_target_files SIGN_TARGET_FILES_APKS=$TOOL_DIR/releasetools/sign_target_files_apks OUT_ZIP_FILE= NO_SIGN=false -CERTIFICATE_DIR=$PORT_ROOT/build/security - -APKCERT=$PORT_ROOT/miui/metadata/apkcert.txt -if [ "$USE_ANDROID_OUT" == "true" ];then - APKCERT=$ANDROID_OUT/obj/PACKAGING/apkcerts_intermediates/*.txt -fi -FILESYSTEM_CONFIG=$PORT_ROOT/miui/metadata/filesystem_config.txt -if [ "$USE_ANDROID_OUT" == "true" ];then - FILESYSTEM_CONFIG=$(find $ANDROID_OUT/obj/PACKAGING/target_files_intermediates/ -name filesystem_config.txt) -fi # copy the whole target_files_template dir function copy_target_files_template { @@ -35,7 +25,7 @@ function copy_bootimage { do if [ -f $ZIP_DIR/$file ] then - cp $ZIP_DIR/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/ + cp $ZIP_DIR/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/boot.img return fi done @@ -56,7 +46,7 @@ function copy_data_dir { fi echo "Copy miui preinstall apps" mkdir -p $TARGET_FILES_DIR/DATA/ - cp -rf $ZIP_DIR/data/miui $TARGET_FILES_DIR/DATA/ + cp -rf $ZIP_DIR/data/media/preinstall_apps $TARGET_FILES_DIR/DATA/ if [ -f customize_data.sh ];then ./customize_data.sh $PRJ_DIR fi @@ -70,19 +60,12 @@ function recover_link { function process_metadata { echo "Process metadata" - cp -f $TARGET_FILES_TEMPLATE_DIR/META/filesystem_config.txt $TARGET_FILES_DIR/META - python $TOOL_DIR/uniq_first.py $METADATA_DIR/filesystem_config.txt $TARGET_FILES_DIR/META/filesystem_config.txt - python $TOOL_DIR/uniq_first.py $FILESYSTEM_CONFIG $TARGET_FILES_DIR/META/filesystem_config.txt - cat $TARGET_FILES_DIR/META/filesystem_config.txt | sort > $TARGET_FILES_DIR/META/temp.txt - mv $TARGET_FILES_DIR/META/temp.txt $TARGET_FILES_DIR/META/filesystem_config.txt - + cp -f $METADATA_DIR/filesystem_config.txt $TARGET_FILES_DIR/META + cat $TOOL_DIR/target_files_template/META/filesystem_config.txt >> $TARGET_FILES_DIR/META/filesystem_config.txt cp -f $METADATA_DIR/recovery.fstab $TARGET_FILES_DIR/RECOVERY/RAMDISK/etc - - cp -rf $APKCERT $TARGET_FILES_DIR/META/apkcerts.txt - python $TOOL_DIR/uniq_first.py $METADATA_DIR/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt - python $TOOL_DIR/uniq_first.py $TARGET_FILES_TEMPLATE_DIR/META/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt - cat $TARGET_FILES_DIR/META/apkcerts.txt | sort > $TARGET_FILES_DIR/META/temp.txt - mv $TARGET_FILES_DIR/META/temp.txt $TARGET_FILES_DIR/META/apkcerts.txt + python $TOOL_DIR/uniq_first.py $METADATA_DIR/apkcerts.txt $TARGET_FILES_DIR/META/apkcerts.txt $PRJ_DIR + cat $TARGET_FILES_DIR/META/apkcerts.txt | sort > $TARGET_FILES_DIR/temp.txt + mv $TARGET_FILES_DIR/temp.txt $TARGET_FILES_DIR/META/apkcerts.txt recover_link } @@ -98,39 +81,20 @@ function zip_target_files { function sign_target_files { echo "Sign target files" - $SIGN_TARGET_FILES_APKS -d $CERTIFICATE_DIR $TARGET_FILES_ZIP temp.zip + $SIGN_TARGET_FILES_APKS -d $PORT_ROOT/build/security $TARGET_FILES_ZIP temp.zip mv temp.zip $TARGET_FILES_ZIP } # build a new full ota package function build_ota_package { echo "Build full ota package: $OUT_DIR/$OUT_ZIP_FILE" - $OTA_FROM_TARGET_FILES -n -k $CERTIFICATE_DIR/testkey $TARGET_FILES_ZIP $OUT_DIR/$OUT_ZIP_FILE + $OTA_FROM_TARGET_FILES -n -k $PORT_ROOT/build/security/testkey $TARGET_FILES_ZIP $OUT_DIR/$OUT_ZIP_FILE } -function adjust_replace_key_script { - if [ "$CERTIFICATE_DIR" != "$PORT_ROOT/build/security" -a -f "$CERTIFICATE_DIR/platform.x509.pem" \ - -a -f "$CERTIFICATE_DIR/shared.x509.pem" -a -f "$CERTIFICATE_DIR/media.x509.pem" -a -f "$CERTIFICATE_DIR/shared.x509.pem" ];then - platform_cert=$(cat $CERTIFICATE_DIR/platform.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_platform/$platform_cert/g" out/target_files/OTA/bin/replace_key - shared_cert=$(cat $CERTIFICATE_DIR/shared.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_shared/$shared_cert/g" out/target_files/OTA/bin/replace_key - media_cert=$(cat $CERTIFICATE_DIR/media.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_media/$media_cert/g" out/target_files/OTA/bin/replace_key - testkey_cert=$(cat $CERTIFICATE_DIR/shared.x509.pem | sed 's/-----/#/g' | cut -d'#' -f1 | tr -d ["\n"] | base64 --decode | hexdump -v -e '/1 "%02x"') - sed -i "s/@user_testkey/$testkey_cert/g" out/target_files/OTA/bin/replace_key - else - rm -rf out/target_files/OTA/bin/replace_key - fi -} if [ $# -eq 3 ];then + NO_SIGN=true OUT_ZIP_FILE=$3 - if [ "$2" == "-n" ];then - NO_SIGN=true - elif [ -n "$2" ];then - CERTIFICATE_DIR=$2 - fi INCLUDE_THIRDPART_APP=$1 elif [ $# -eq 2 ];then OUT_ZIP_FILE=$2 @@ -139,13 +103,7 @@ elif [ $# -eq 1 ];then INCLUDE_THIRDPART_APP=$1 fi -#Set certificate pass word -if [ -f "$CERTIFICATE_DIR/passwd" ];then - export ANDROID_PW_FILE=$CERTIFICATE_DIR/passwd -fi - copy_target_files_template -adjust_replace_key_script copy_bootimage copy_system_dir copy_data_dir diff --git a/darwin-x86/aapt b/darwin-x86/aapt deleted file mode 100755 index 2a0db5d..0000000 Binary files a/darwin-x86/aapt and /dev/null differ diff --git a/darwin-x86/bsdiff b/darwin-x86/bsdiff deleted file mode 100755 index 0f5cd34..0000000 Binary files a/darwin-x86/bsdiff and /dev/null differ diff --git a/darwin-x86/imgdiff b/darwin-x86/imgdiff deleted file mode 100755 index d9eba10..0000000 Binary files a/darwin-x86/imgdiff and /dev/null differ diff --git a/darwin-x86/lib64/libcutils.dylib b/darwin-x86/lib64/libcutils.dylib deleted file mode 100755 index 18d64f0..0000000 Binary files a/darwin-x86/lib64/libcutils.dylib and /dev/null differ diff --git a/darwin-x86/lib64/liblog.dylib b/darwin-x86/lib64/liblog.dylib deleted file mode 100755 index 412814f..0000000 Binary files a/darwin-x86/lib64/liblog.dylib and /dev/null differ diff --git a/darwin-x86/mkbootfs b/darwin-x86/mkbootfs deleted file mode 100755 index f190aee..0000000 Binary files a/darwin-x86/mkbootfs and /dev/null differ diff --git a/darwin-x86/mkbootimg b/darwin-x86/mkbootimg deleted file mode 100755 index f3f1d16..0000000 Binary files a/darwin-x86/mkbootimg and /dev/null differ diff --git a/darwin-x86/unpackbootimg b/darwin-x86/unpackbootimg deleted file mode 100755 index 5c97816..0000000 Binary files a/darwin-x86/unpackbootimg and /dev/null differ diff --git a/darwin-x86/zipalign b/darwin-x86/zipalign deleted file mode 100755 index 0e3827d..0000000 Binary files a/darwin-x86/zipalign and /dev/null differ diff --git a/deoat.sh b/deoat.sh deleted file mode 100755 index 97f9206..0000000 --- a/deoat.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2016, Miui Patchrom -# - -TARGET_DIR=$1 - -function removeDuplicateFiles() { - local bootOat64Path=$(find $TARGET_DIR -name "boot.oat" | grep "64\/") - if [ -n $bootOat64Path ];then - rm -rf ${bootOat64Path/64\///} - rm -rf ${bootOat64Path/64\/boot.oat//boot.art} - fi - local odex - for odex in $(find $TARGET_DIR -name "*.odex" | grep "64\/") - do - echo "rm -rf ${odex/64\///}" - rm -rf ${odex/64\///} - done -} - -function zipDex() { - local zipDir=$1 - local dexPath=$2 - local suffix=$3 - local dexName=$(basename $dexPath .dex) - local zipName=${dexName%%-classes*} - if [ $dexName = $zipName ];then - local zipDexName=classes.dex - else - local zipDexName=classes${dexName##*-classes}.dex - fi - mv $dexPath $zipDexName - if [ -f $zipDir/$zipName.$suffix ];then - zip -m $zipDir/$zipName.$suffix $zipDexName > /dev/null - fi -} - -function decodeBootOat() { - BOOTOAT_PATH=$(find $TARGET_DIR -name "boot.oat") - if [ -z $BOOTOAT_PATH ];then - return - fi - BOOTOAT_DIR=$(dirname $BOOTOAT_PATH) - echo "Decoding $BOOTOAT_PATH" - oat2dex boot $BOOTOAT_PATH > /dev/null - local bootDex - for bootDex in $(find $BOOTOAT_DIR/dex -name "*.dex") - do - zipDex $(dirname $BOOTOAT_DIR) $bootDex jar - done -} - -function decodeOdex() { - local suffix=$1 - local zipPath - for zipPath in $(find $TARGET_DIR -name "*.$suffix") - do - local zipDir=$(dirname $zipPath) - local zipName=$(basename $zipPath) - local odexPath=$(find $zipDir -name ${zipName/.$suffix/.odex}) - if [ -z $odexPath ];then - continue - fi - echo "Decoding $odexPath" - local bootClassPath=$BOOTOAT_DIR/odex - if [ "$suffix" = "apk" ];then - bootClassPath=$(dirname $BOOTOAT_DIR) - fi - local ret=$(oat2dex -o $zipDir $odexPath $bootClassPath) - if [ -n "$(echo $ret | grep -i "failed")" -a -f $PORT_ROOT/tools/oat2dex-0.86.jar ];then - echo "Decoding $odexPath failed, try to use old version oat2dex" - java -jar $PORT_ROOT/tools/oat2dex-0.86.jar -o $zipDir $odexPath $bootClassPath > /dev/null - fi - rm -rf $odexPath - local dexPath - for dexPath in $(find $zipDir -maxdepth 1 -name "*.dex") - do - zipDex $zipDir $dexPath $suffix - done - done -} - -removeDuplicateFiles -decodeBootOat -decodeOdex jar -decodeOdex apk -rm -rf $BOOTOAT_DIR/boot.oat $BOOTOAT_DIR/boot.art $BOOTOAT_DIR/odex $BOOTOAT_DIR/dex diff --git a/deodex.sh b/deodex.sh index 1ecd2f8..4e3da55 100755 --- a/deodex.sh +++ b/deodex.sh @@ -12,13 +12,13 @@ function deodex_one_file() { file=$4 tofile=${file/odex/$5} echo "processing $tofile" - $BAKSMALI -a $apilevel -c $classpath -d framework -x $file || exit -2 + $BAKSMALI -a $apilevel -c $classpath -d framework -I -x $file || exit -2 else classpath=$1 file=$2 tofile=${file/odex/$3} echo "processing $tofile" - $BAKSMALI -c $classpath -d framework -x $file || exit -2 + $BAKSMALI -c $classpath -d framework -I -x $file || exit -2 fi $SMALI out -o classes.dex || exit -2 jar uf $tofile classes.dex @@ -71,12 +71,11 @@ fi ls framework/core.odex > /dev/null if [ $? -eq 0 ] then - classpath="core.jar:ext.jar:framework.jar:android.policy.jar:services.jar" if [ $1 = '-a' ] then - deodex_one_file -a $apilevel $classpath framework/core.odex jar + deodex_one_file -a $apilevel "" framework/core.odex jar else - deodex_one_file $classpath framework/core.odex jar + deodex_one_file "" framework/core.odex jar fi fi diff --git a/fix_9patch_png.sh b/fix_9patch_png.sh deleted file mode 100755 index a0186b3..0000000 --- a/fix_9patch_png.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# -# Fix Grayscale PNG conversion increase brightness bug -# Bug discription -# APKTOOL issue id: 326 -# JDK bug uri: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5051418 -# Root cause -# 1.when apktool decode gray adn gray-alpha 9Patch png, -# it will use jdk drawImage() method, and the method -# has a bug which increase brightness. -# 2.the bug is only exist 9Patch png, other png without -# the problem, as apktool won't decode it. -# Fix method -# 1.unzip original and target apk, not use apktool. -# 2.copy 9Patch pngs from original apk to target apk. -# 3.re-zip taget apk. -# $1: the original apk name -# $2: the original apk dir -# $3: the out dir -# $4: filter dir -# $5: filter dir - -APK_FILE=$1.apk -ORIGINAL_APK=$2/$APK_FILE -REPLACE_APK=$3/$APK_FILE - -TMP_ORIGINAL_FILE=$3/$1-original.apk -TMP_TARGET_FILE=$3/$1-target.apk - -TMP_ORIGINAL_DIR=$3/$1-original -TMP_TARGET_DIR=$3/$1-target - -HAS_FILTER1=false -HAS_FILTER2=false -if [ $# -gt 3 ];then - HAS_FILTER1=true -fi -if [ $# -gt 4 ];then - HAS_FILTER2=true -fi - -cp -r $ORIGINAL_APK $TMP_ORIGINAL_FILE -mv $REPLACE_APK $TMP_TARGET_FILE -unzip -o $TMP_ORIGINAL_FILE -d $TMP_ORIGINAL_DIR > /dev/null -unzip -o $TMP_TARGET_FILE -d $TMP_TARGET_DIR > /dev/null -for file in `find $TMP_ORIGINAL_DIR -name *.9.png`; do - targetfile=`echo $file | sed -e "s/-original/-target/"` - overlay=`echo $file | sed -e "s/$3\/$1-original\/res\///"` - if [ "$HAS_FILTER1" == "true" -a -f $4/$overlay ];then - continue - elif [ "$HAS_FILTER2" == "true" -a -f $5/$overlay ];then - continue - fi - cp $file $targetfile -done -cd $TMP_TARGET_DIR -#only store all files, not compress files -#as raw resource can't be compressed. -zip -r0 ../$APK_FILE ./ > /dev/null diff --git a/gen_res_conf.sh b/gen_res_conf.sh deleted file mode 100755 index 9bae7a4..0000000 --- a/gen_res_conf.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -CONF=$1 -APKDIR=$2 -SYSDIR=$3 - -for line in `cat $CONF` -do - name=`echo $line | cut -d= -f1` - value=`echo $line | cut -d= -f2` - echo $line - [$name] [$value] - - if [ "$name" = "APK" ]; then - apkfile=$value - elif [ "$name" = "package" ]; then - package=$value - rm -f $SYSDIR/res_overlay_$package.txt - echo "Generate conf file:$SYSDIR/res_overlay_$package.txt" - else - resv=`aapt d resources $APKDIR/$apkfile | sed -n -e "s/^.*spec resource 0x\(.*\) .*$name.*$/\1/p"` - echo "$name=$resv" >> $SYSDIR/res_overlay_$package.txt - echo " Add $name=$resv" - fi -done - diff --git a/get_apk_cert.py b/get_apk_cert.py deleted file mode 100755 index 7797e05..0000000 --- a/get_apk_cert.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2016 The Miui Patchrom -# - -import os -import sys -import re - -# Values for "certificate" in apkcerts that mean special things. -SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") -PUBLIC_KEY_SUFFIX = ".x509.pem" -PRIVATE_KEY_SUFFIX = ".pk8" - - -def ReadApkCerts(apkcerts): - """parse the apkcerts.txt file and return a {package: cert} dict.""" - certmap = {} - with open(apkcerts, 'r') as certs: - for line in certs.readlines(): - m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' - r'private_key="(.*)"$', line) - if m: - name, cert, privkey = m.groups() - public_key_suffix_len = len(PUBLIC_KEY_SUFFIX) - private_key_suffix_len = len(PRIVATE_KEY_SUFFIX) - if cert in SPECIAL_CERT_STRINGS and not privkey: - certmap[name] = cert - elif (cert.endswith(PUBLIC_KEY_SUFFIX) and - privkey.endswith(PRIVATE_KEY_SUFFIX) and - cert[:-public_key_suffix_len] == privkey[:-private_key_suffix_len]): - certmap[name] = cert[:-public_key_suffix_len] - else: - raise ValueError("failed to parse line from apkcerts.txt:\n" + line) - return certmap - -if __name__ == '__main__': - apkPath = sys.argv[1] - apkCerts = sys.argv[2] - certmap = ReadApkCerts(apkCerts) - cert = os.path.basename(certmap[os.path.basename(apkPath)]) - print cert diff --git a/get_filesystem_config b/get_filesystem_config deleted file mode 100755 index ddbdf8f..0000000 --- a/get_filesystem_config +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2016, Miui Patchrom -# - -ACTION=$1 -LINE_TERMINATION=$'\r\n' -OLD_IFS=$IFS -IFS=$'\n' -BUSYBOX="$2" -if [ -n "$(adb shell id | grep "uid=0")" ];then - root='true' -elif [ -z "$(adb shell su -c "id" | grep "uid=0")" ];then - echo "Please root your device, and try again." - exit 1 -fi - -if [ -n $root ];then - fileSystemInfo=$(adb shell ls -aRZ /system) -else - fileSystemInfo=$(adb shell su -c "ls -aRZ /system") -fi - -if [ "$ACTION" = '--info' ];then - for line in $fileSystemInfo - do - if [ $line == $LINE_TERMINATION -o ${line:0:1} == 'd' ];then - continue - fi - # lrwxrwxrwx root root u:object_r:system_file:s0 chmod -> toybox - # cut line before the string " ->" - line=${line%% ->*} - if [ $(echo $line | cut -d ':' -f2) == $LINE_TERMINATION ];then - dir=$(echo $line | cut -d ':' -f1) - path=$dir - if [ -n $root ];then - line=$(adb shell ls -dZ $path) - else - line=$(adb shell su -c "ls -dZ $path") - fi - else - path=$dir/$(echo ${line##*:s0} | tr -d $LINE_TERMINATION | sed 's/^[ ]*//') - fi - selabel="u:${line##*u:}" - selabel=${selabel%% *} - if [ -n $root ];then - uid=$(adb shell $BUSYBOX stat -c %u $path | tr -d $LINE_TERMINATION) - gid=$(adb shell $BUSYBOX stat -c %g $path | tr -d $LINE_TERMINATION) - perm=$(adb shell $BUSYBOX stat -c %a $path | tr -d $LINE_TERMINATION) - else - uid=$(adb shell su -c "$BUSYBOX stat -c %u $path" | tr -d $LINE_TERMINATION) - gid=$(adb shell su -c "$BUSYBOX stat -c %g $path" | tr -d $LINE_TERMINATION) - perm=$(adb shell su -c "$BUSYBOX stat -c %a $path" | tr -d $LINE_TERMINATION) - fi - #Remove blank in filename, it cause ota_from_target_files failed. - path=$(echo $path | sed 's/ //g') - echo "${path#\/} $uid $gid $perm selabel=$selabel capabilities=0x0" - done -elif [ "$ACTION" = '--link' ];then - for line in $fileSystemInfo - do - if [ $line == $LINE_TERMINATION];then - continue - fi - line=${line%% ->*} - if [ $(echo $line | cut -d ':' -f2) == $LINE_TERMINATION ];then - dir=$(echo $line | cut -d ':' -f1) - path=$dir - if [ -n $root ];then - line=$(adb shell ls -dZ $path) - else - line=$(adb shell su -c "ls -dZ $path") - fi - fi - - if [ ${line:0:1} == 'l' ];then - path=$dir/$(echo ${line##*:s0} | tr -d $LINE_TERMINATION | sed 's/^[ ]*//') - if [ -n $root ];then - link=$(adb shell $BUSYBOX readlink $path | tr -d $LINE_TERMINATION) - else - link=$(adb shell su -c "$BUSYBOX readlink $path" | tr -d $LINE_TERMINATION) - fi - echo "${path#\/}|$link" - fi - done -fi diff --git a/hex_replace.py b/hex_replace.py deleted file mode 100644 index 818c1ec..0000000 --- a/hex_replace.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env pyhon - -from sys import argv -import struct - -def usage(): - print "Usage: %s orignal target file" % argv[0] - - -def do_replace(inFile, outFile, oldHex, newHex): - inFp = open(inFile, 'rb') - outFp = open(outFile, 'wb') - oldstr = struct.pack('LH', 4611950241719001088, 18288) - newstr = struct.pack('LH', 5147649559655096320, 18112) - while 1: - s = inFp.read(10) - if s: - print struct.unpack('LH', s) - if s == oldstr: - print "replace" - outFp.write(newstr) - else: - outFp.write(s) - else: - break - - inFp.close() - outFp.close() - - - -if __name__ == "__main__": - #if len(argv) < 4: - # exit(usage()) - - do_replace(argv[1], argv[2], 0, 0) - - diff --git a/insertkeys.py b/insertkeys.py deleted file mode 100755 index ca1e432..0000000 --- a/insertkeys.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python - -from xml.sax import saxutils, handler, make_parser -from optparse import OptionParser -import ConfigParser -import logging -import base64 -import sys -import os - -__VERSION = (0, 1) - -''' -This tool reads a mac_permissions.xml and replaces keywords in the signature -clause with keys provided by pem files. -''' - -class GenerateKeys(object): - def __init__(self, path): - ''' - Generates an object with Base16 and Base64 encoded versions of the keys - found in the supplied pem file argument. PEM files can contain multiple - certs, however this seems to be unused in Android as pkg manager grabs - the first cert in the APK. This will however support multiple certs in - the resulting generation with index[0] being the first cert in the pem - file. - ''' - - self._base64Key = list() - self._base16Key = list() - - if not os.path.isfile(path): - sys.exit("Path " + path + " does not exist or is not a file!") - - pkFile = open(path, 'rb').readlines() - base64Key = "" - lineNo = 1 - certNo = 1 - inCert = False - for line in pkFile: - line = line.strip() - # Are we starting the certificate? - if line == "-----BEGIN CERTIFICATE-----": - if inCert: - sys.exit("Encountered another BEGIN CERTIFICATE without END CERTIFICATE on " + - "line: " + str(lineNo)) - - inCert = True - - # Are we ending the ceritifcate? - elif line == "-----END CERTIFICATE-----": - if not inCert: - sys.exit("Encountered END CERTIFICATE before BEGIN CERTIFICATE on line: " - + str(lineNo)) - - # If we ended the certificate trip the flag - inCert = False - - # Sanity check the input - if len(base64Key) == 0: - sys.exit("Empty certficate , certificate "+ str(certNo) + " found in file: " - + path) - - # ... and append the certificate to the list - # Base 64 includes uppercase. DO NOT tolower() - self._base64Key.append(base64Key) - try: - # Pkgmanager and setool see hex strings with lowercase, lets be consistent - self._base16Key.append(base64.b16encode(base64.b64decode(base64Key)).lower()) - except TypeError: - sys.exit("Invalid certificate, certificate "+ str(certNo) + " found in file: " - + path) - - # After adding the key, reset the accumulator as pem files may have subsequent keys - base64Key="" - - # And increment your cert number - certNo = certNo + 1 - - # If we haven't started the certificate, then we should not encounter any data - elif not inCert: - if line is not "": - sys.exit("Detected erroneous line \""+ line + "\" on " + str(lineNo) - + " in pem file: " + path) - - # else we have started the certicate and need to append the data - elif inCert: - base64Key += line - - else: - # We should never hit this assert, if we do then an unaccounted for state - # was entered that was NOT addressed by the if/elif statements above - assert(False == True) - - # The last thing to do before looping up is to increment line number - lineNo = lineNo + 1 - - def __len__(self): - return len(self._base16Key) - - def __str__(self): - return str(self.getBase16Keys()) - - def getBase16Keys(self): - return self._base16Key - - def getBase64Keys(self): - return self._base64Key - -class ParseConfig(ConfigParser.ConfigParser): - - # This must be lowercase - OPTION_WILDCARD_TAG = "all" - - def generateKeyMap(self, target_build_variant, key_directory): - - keyMap = dict() - - for tag in self.sections(): - - options = self.options(tag) - - for option in options: - - # Only generate the key map for debug or release, - # not both! - if option != target_build_variant and \ - option != ParseConfig.OPTION_WILDCARD_TAG: - logging.info("Skipping " + tag + " : " + option + - " because target build variant is set to " + - str(target_build_variant)) - continue - - if tag in keyMap: - sys.exit("Duplicate tag detected " + tag) - - tag_path = os.path.expandvars(self.get(tag, option)) - path = os.path.join(key_directory, tag_path) - - keyMap[tag] = GenerateKeys(path) - - # Multiple certificates may exist in - # the pem file. GenerateKeys supports - # this however, the mac_permissions.xml - # as well as PMS do not. - assert len(keyMap[tag]) == 1 - - return keyMap - -class ReplaceTags(handler.ContentHandler): - - DEFAULT_TAG = "default" - PACKAGE_TAG = "package" - POLICY_TAG = "policy" - SIGNER_TAG = "signer" - SIGNATURE_TAG = "signature" - - TAGS_WITH_CHILDREN = [ DEFAULT_TAG, PACKAGE_TAG, POLICY_TAG, SIGNER_TAG ] - - XML_ENCODING_TAG = '' - - def __init__(self, keyMap, out=sys.stdout): - - handler.ContentHandler.__init__(self) - self._keyMap = keyMap - self._out = out - self._out.write(ReplaceTags.XML_ENCODING_TAG) - self._out.write("") - self._out.write("") - - def __del__(self): - self._out.write("") - - def startElement(self, tag, attrs): - if tag == ReplaceTags.POLICY_TAG: - return - - self._out.write('<' + tag) - - for (name, value) in attrs.items(): - - if name == ReplaceTags.SIGNATURE_TAG and value in self._keyMap: - for key in self._keyMap[value].getBase16Keys(): - logging.info("Replacing " + name + " " + value + " with " + key) - self._out.write(' %s="%s"' % (name, saxutils.escape(key))) - else: - self._out.write(' %s="%s"' % (name, saxutils.escape(value))) - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('>') - else: - self._out.write('/>') - - def endElement(self, tag): - if tag == ReplaceTags.POLICY_TAG: - return - - if tag in ReplaceTags.TAGS_WITH_CHILDREN: - self._out.write('' % tag) - - def characters(self, content): - if not content.isspace(): - self._out.write(saxutils.escape(content)) - - def ignorableWhitespace(self, content): - pass - - def processingInstruction(self, target, data): - self._out.write('' % (target, data)) - -if __name__ == "__main__": - - # Intentional double space to line up equls signs and opening " for - # readability. - usage = "usage: %prog [options] CONFIG_FILE MAC_PERMISSIONS_FILE [MAC_PERMISSIONS_FILE...]\n" - usage += "This tool allows one to configure an automatic inclusion\n" - usage += "of signing keys into the mac_permision.xml file(s) from the\n" - usage += "pem files. If mulitple mac_permision.xml files are included\n" - usage += "then they are unioned to produce a final version." - - version = "%prog " + str(__VERSION) - - parser = OptionParser(usage=usage, version=version) - - parser.add_option("-v", "--verbose", - action="store_true", dest="verbose", default=False, - help="Print internal operations to stdout") - - parser.add_option("-o", "--output", default="stdout", dest="output_file", - metavar="FILE", help="Specify an output file, default is stdout") - - parser.add_option("-c", "--cwd", default=os.getcwd(), dest="root", - metavar="DIR", help="Specify a root (CWD) directory to run this from, it" \ - "chdirs' AFTER loading the config file") - - parser.add_option("-t", "--target-build-variant", default="eng", dest="target_build_variant", - help="Specify the TARGET_BUILD_VARIANT, defaults to eng") - - parser.add_option("-d", "--key-directory", default="", dest="key_directory", - help="Specify a parent directory for keys") - - (options, args) = parser.parse_args() - - if len(args) < 2: - parser.error("Must specify a config file (keys.conf) AND mac_permissions.xml file(s)!") - - logging.basicConfig(level=logging.INFO if options.verbose == True else logging.WARN) - - # Read the config file - config = ParseConfig() - config.read(args[0]) - - os.chdir(options.root) - - output_file = sys.stdout if options.output_file == "stdout" else open(options.output_file, "w") - logging.info("Setting output file to: " + options.output_file) - - # Generate the key list - key_map = config.generateKeyMap(options.target_build_variant.lower(), options.key_directory) - logging.info("Generate key map:") - for k in key_map: - logging.info(k + " : " + str(key_map[k])) - # Generate the XML file with markup replaced with keys - parser = make_parser() - parser.setContentHandler(ReplaceTags(key_map, output_file)) - for f in args[1:]: - parser.parse(f) diff --git a/keys.conf b/keys.conf deleted file mode 100644 index 7a307b5..0000000 --- a/keys.conf +++ /dev/null @@ -1,25 +0,0 @@ -# -# Maps an arbitrary tag [TAGNAME] with the string contents found in -# TARGET_BUILD_VARIANT. Common convention is to start TAGNAME with an @ and -# name it after the base file name of the pem file. -# -# Each tag (section) then allows one to specify any string found in -# TARGET_BUILD_VARIANT. Typcially this is user, eng, and userdebug. Another -# option is to use ALL which will match ANY TARGET_BUILD_VARIANT string. -# - -[@PLATFORM] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/platform.x509.pem - -[@MEDIA] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/media.x509.pem - -[@SHARED] -ALL : $DEFAULT_SYSTEM_DEV_CERTIFICATE/shared.x509.pem - -# Example of ALL TARGET_BUILD_VARIANTS -[@RELEASE] -ENG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem -USER : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem -USERDEBUG : $DEFAULT_SYSTEM_DEV_CERTIFICATE/testkey.x509.pem - diff --git a/linux-x86/aapt b/linux-x86/aapt deleted file mode 100755 index 9a119c4..0000000 Binary files a/linux-x86/aapt and /dev/null differ diff --git a/linux-x86/lib/libc++.so b/linux-x86/lib/libc++.so deleted file mode 100755 index 0101d43..0000000 Binary files a/linux-x86/lib/libc++.so and /dev/null differ diff --git a/linux-x86/mkbootimg b/linux-x86/mkbootimg deleted file mode 100755 index 8b3b315..0000000 Binary files a/linux-x86/mkbootimg and /dev/null differ diff --git a/linux-x86/unpackbootimg b/linux-x86/unpackbootimg deleted file mode 100755 index 1c4eac2..0000000 Binary files a/linux-x86/unpackbootimg and /dev/null differ diff --git a/linux-x86/zipalign b/linux-x86/zipalign deleted file mode 100755 index 8186151..0000000 Binary files a/linux-x86/zipalign and /dev/null differ diff --git a/make_key b/make_key deleted file mode 100755 index 03ed880..0000000 --- a/make_key +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Generates a public/private key pair suitable for use in signing -# android .apks and OTA update packages. - -if [ "$#" -lt 2 -o "$#" -gt 3 ]; then - cat < [] - -Creates .pk8 key and .x509.pem cert. Cert contains the -given . A keytype of "rsa" or "ec" is accepted. -EOF - exit 2 -fi - -if [[ -e $1.pk8 || -e $1.x509.pem ]]; then - echo "$1.pk8 and/or $1.x509.pem already exist; please delete them first" - echo "if you want to replace them." - exit 1 -fi - -# Use named pipes to connect get the raw RSA private key to the cert- -# and .pk8-creating programs, to avoid having the private key ever -# touch the disk. - -tmpdir=$(mktemp -d) -trap 'rm -rf ${tmpdir}; echo; exit 1' EXIT INT QUIT - -one=${tmpdir}/one -two=${tmpdir}/two -mknod ${one} p -mknod ${two} p -chmod 0600 ${one} ${two} - -read -p "Enter password for '$1' (blank for none; password will be visible): " \ - password - -export RANDFILE=".rnd" - -if [ "${3}" = "rsa" -o "$#" -eq 2 ]; then - ( openssl genrsa -f4 2048 | tee ${one} > ${two} ) & - hash="-sha1" -elif [ "${3}" = "ec" ]; then - ( openssl ecparam -name prime256v1 -genkey -noout | tee ${one} > ${two} ) & - hash="-sha256" -else - echo "Only accepts RSA or EC keytypes." - exit 1 -fi - -openssl req -new -x509 ${hash} -key ${two} -out $1.x509.pem \ - -days 10000 -subj "$2" & - -if [ "${password}" == "" ]; then - echo "creating ${1}.pk8 with no password" - openssl pkcs8 -in ${one} -topk8 -outform DER -out $1.pk8 -nocrypt -else - echo "creating ${1}.pk8 with password [${password}]" - export password - openssl pkcs8 -in ${one} -topk8 -outform DER -out $1.pk8 \ - -passout env:password - unset password -fi - -wait -wait diff --git a/linux-x86/mkbootfs b/mkbootfs similarity index 100% rename from linux-x86/mkbootfs rename to mkbootfs diff --git a/mkbootimg b/mkbootimg new file mode 100755 index 0000000..6ff4b84 Binary files /dev/null and b/mkbootimg differ diff --git a/oat2dex b/oat2dex deleted file mode 100755 index f91a83f..0000000 --- a/oat2dex +++ /dev/null @@ -1,83 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2007 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# As per the Apache license requirements, this file has been modified -# from its original state. -# -# Such modifications are Copyright (C) 2016 Miui Patchrom Project, and -# are released under the original license - -# This script is a wrapper around oat2dex.jar, so you can simply call -# "oat2dex", instead of java -jar oat2dex.jar. It is heavily based on -# the "dx" script from the Android SDK - -# Set up prog to be the path of this script, including following symlinks, -# and set up progdir to be the fully-qualified pathname of its directory. -prog="$0" -while [ -h "${prog}" ]; do - newProg=`/bin/ls -ld "${prog}"` - echo ${newProg} - - - newProg=`expr "${newProg}" : ".* -> \(.*\)$"` - if expr "x${newProg}" : 'x/' >/dev/null; then - prog="${newProg}" - else - progdir=`dirname "${prog}"` - prog="${progdir}/${newProg}" - fi -done -oldwd=`pwd` -progdir=`dirname "${prog}"` -cd "${progdir}" -progdir=`pwd` -prog="${progdir}"/`basename "${prog}"` -cd "${oldwd}" - - -jarfile=oat2dex.jar -libdir="$progdir" -if [ ! -r "$libdir/$jarfile" ] -then - echo `basename "$prog"`": can't find $jarfile" - exit 1 -fi - -javaOpts="" - -# If you want DX to have more memory when executing, uncomment the following -# line and adjust the value accordingly. Use "java -X" for a list of options -# you can pass here. -# -javaOpts="-Xmx1024M" - -# Alternatively, this will extract any parameter "-Jxxx" from the command line -# and pass them to Java (instead of to dx). This makes it possible for you to -# add a command-line parameter such as "-JXmx256M" in your ant scripts, for -# example. -while expr "x$1" : 'x-J' >/dev/null; do - opt=`expr "$1" : '-J\(.*\)'` - javaOpts="${javaOpts} -${opt}" - shift -done - -if [ "$OSTYPE" = "cygwin" ] ; then - jarpath=`cygpath -w "$libdir/$jarfile"` -else - jarpath="$libdir/$jarfile" -fi - -exec java $javaOpts -jar "$jarpath" "$@" diff --git a/oat2dex-0.86.jar b/oat2dex-0.86.jar deleted file mode 100644 index 8f1a611..0000000 Binary files a/oat2dex-0.86.jar and /dev/null differ diff --git a/oat2dex-0.87.jar b/oat2dex-0.87.jar deleted file mode 100644 index bf0eab8..0000000 Binary files a/oat2dex-0.87.jar and /dev/null differ diff --git a/oat2dex.jar b/oat2dex.jar deleted file mode 120000 index 696f33d..0000000 --- a/oat2dex.jar +++ /dev/null @@ -1 +0,0 @@ -oat2dex-0.87.jar \ No newline at end of file diff --git a/patch_bootimg.sh b/patch_bootimg.sh deleted file mode 100755 index 17f0775..0000000 --- a/patch_bootimg.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -if [ -f "./patch_bootimg.sh" ];then - bash ./patch_bootimg.sh $1 - exit $? -fi - -BOOTIMG=$1 - -# Unpack bootimg -rm -rf $TARGET_BOOT_DIR -mkdir -p $TARGET_BOOT_DIR -$UNPACKBOOTIMG -i $BOOTIMG -o $TARGET_BOOT_DIR > /dev/null - -# Unpack ramdisk -gunzip $TARGET_BOOT_DIR/boot.img-ramdisk.gz -mkdir -p $TARGET_BOOT_DIR/ramdisk -cd $TARGET_BOOT_DIR/ramdisk -cpio -i < ../boot.img-ramdisk -cd - > /dev/null - -# Change init -if [ ! -f $TARGET_BOOT_DIR/ramdisk/init_vendor ];then -mv $TARGET_BOOT_DIR/ramdisk/init $TARGET_BOOT_DIR/ramdisk/init_vendor -fi -cp -f $PREBUILT_BOOT_DIR/$TARGET_BIT/init $TARGET_BOOT_DIR/ramdisk/init - -# Pack ramdisk -$MKBOOTFS $TARGET_BOOT_DIR/ramdisk | gzip > $TARGET_BOOT_DIR/ramdisk.gz - - -# Disable selinux -OLDCMDLINE=$(cat $TARGET_BOOT_DIR/boot.img-cmdline) -NEWCMDLINE="androidboot.selinux=disabled" -for prop in $OLDCMDLINE -do - echo $prop | grep "androidboot.selinux=" > /dev/null - if [ $? -eq 0 ];then - continue - fi - NEWCMDLINE="$NEWCMDLINE $prop" -done - -echo "NEWCMDLINE: $NEWCMDLINE" - -BASEADDR=$(cat $TARGET_BOOT_DIR/boot.img-base) -PAGESIZE=$(cat $TARGET_BOOT_DIR/boot.img-pagesize) -RAMDISKOFFSET=$(cat $TARGET_BOOT_DIR/boot.img-ramdisk_offset) -TAGSOFFSET=$(cat $TARGET_BOOT_DIR/boot.img-tags_offset) - -# Pack bootimg -$MKBOOTIMG --kernel $TARGET_BOOT_DIR/boot.img-zImage --ramdisk $TARGET_BOOT_DIR/ramdisk.gz --dt $TARGET_BOOT_DIR/boot.img-dt --base "$BASEADDR" --pagesize "$PAGESIZE" --ramdisk_offset "$RAMDISKOFFSET" --tags_offset "$TAGSOFFSET" --cmdline "$NEWCMDLINE" -o $BOOTIMG diff --git a/patch_for_phones.sh b/patch_for_phones.sh index 31f414f..17abe43 100755 --- a/patch_for_phones.sh +++ b/patch_for_phones.sh @@ -7,7 +7,7 @@ then exit fi -ALL_PHONES=$(sed -n '2p' $PORT_ROOT/build/makefile | sed 's/PRODUCTS := //') +ALL_PHONES=$(sed -n '2p' $PORT_ROOT/Makefile | sed 's/PRODUCTS := //') ALL_PHONES="$ALL_PHONES $EXTRA_PHONES" #set environment variable EXTRA_PHONES to other phones that aren't in Makefile FACTORYS=(HTC HUAWEI SONY MOTO SAMSUNG) @@ -218,7 +218,7 @@ function patch_one_commit { cd "$PORT_ROOT/$from" mkdir $PATCH_SWAP_PATH -p - git.patch ${commit}^..${commit} 2>/dev/null | sed "s/framework2.jar.out/framework.jar.out/g" | sed "s/framework-ext.jar.out/framework.jar.out/g" > ${PATCH_SWAP_PATH}/${from}-patch.${commit} + git.patch ${commit}^..${commit} | sed "s/framework2.jar.out/framework.jar.out/g" | sed "s/framework-ext.jar.out/framework.jar.out/g" > ${PATCH_SWAP_PATH}/${from}-patch.${commit} IFS_OLD="$IFS" IFS= MGS= diff --git a/patch_miui_app.sh b/patch_miui_app.sh index 8cc67ae..bb4d001 100755 --- a/patch_miui_app.sh +++ b/patch_miui_app.sh @@ -10,18 +10,16 @@ if [ -f "customize_miui_app.sh" ]; then fi fi -if [ -f $1 ];then - if [ $1 = "MiuiHome" ];then - if [ -f $1/res/xml/default_workspace.xml.part ]; then - $PORT_ROOT/tools/gen_desklayout.pl $1/res/xml/default_workspace.xml.part $2/res/xml - for file in $2/res/xml/default_workspace*.xml; do - mv $file.new $file - done - fi - fi - - # patch *.smali.method under $1 - for file in `find $1 -name "*.smali.method"`; do - $PORT_ROOT/tools/replace_smali_method.sh apply $file - done +if [ $1 = "MiuiHome" ];then + if [ -f $1/res/xml/default_workspace.xml.part ]; then + $PORT_ROOT/tools/gen_desklayout.pl $1/res/xml/default_workspace.xml.part $2/res/xml + for file in $2/res/xml/default_workspace*.xml; do + mv $file.new $file + done + fi fi + +# patch *.smali.method under $1 +for file in `find $1 -name "*.smali.method"`; do + $PORT_ROOT/tools/replace_smali_method.sh apply $file +done diff --git a/patch_miui_framework.sh b/patch_miui_framework.sh index 7ef2f65..0af8a82 100755 --- a/patch_miui_framework.sh +++ b/patch_miui_framework.sh @@ -80,11 +80,9 @@ function apply_miui_patch() { rm -rf $dst_code_orig } -jar_outs=`find $new_smali_dir -name "*.jar.out"` -for out in $jar_outs -do - apply_miui_patch $(basename $out) -done +apply_miui_patch android.policy.jar.out +apply_miui_patch services.jar.out +apply_miui_patch framework.jar.out echo echo diff --git a/post_process_props.py b/post_process_props.py deleted file mode 100755 index 0387d6e..0000000 --- a/post_process_props.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (C) 2009 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import sys - -# Put the modifications that you need to make into the /system/build.prop into this -# function. The prop object has get(name) and put(name,value) methods. -def mangle_build_prop(prop, overlaylines): - for i in range(0,len(overlaylines)): - pair = overlaylines[i].split('=') - if len(pair) == 2: - name = pair[0].strip() - value = pair[1].strip() - if not name.startswith("#"): - prop.put(name,value) - pass - -class PropFile: - def __init__(self, lines): - self.lines = [s[:-1] for s in lines] - - def get(self, name): - key = name + "=" - for line in self.lines: - if line.startswith(key): - return line[len(key):] - return "" - - def put(self, name, value): - key = name + "=" - for i in range(0,len(self.lines)): - if self.lines[i].startswith(key): - self.lines[i] = key + value - return - self.lines.append(key + value) - - def delete(self, name): - key = name + "=" - i = 0 - while i < len(self.lines): - if self.lines[i].startswith(key): - del self.lines[i] - else: - i += 1 - - def write(self, f): - f.write("\n".join(self.lines)) - f.write("\n") - -def main(argv): - srcfilename = argv[1] - overlayfilename = argv[2] - fs = open(srcfilename) - srclines = fs.readlines() - fs.close() - - fo = open(overlayfilename) - overlaylines = fo.readlines() - fo.close() - - properties = PropFile(srclines) - if srcfilename.endswith("/build.prop"): - mangle_build_prop(properties, overlaylines) - else: - sys.stderr.write("bad command line: " + str(argv) + "\n") - sys.exit(1) - - fs = open(srcfilename, 'w+') - properties.write(fs) - fs.close() - -if __name__ == "__main__": - main(sys.argv) diff --git a/releasetools/blockimgdiff.py b/releasetools/blockimgdiff.py deleted file mode 100644 index 6ed9ca2..0000000 --- a/releasetools/blockimgdiff.py +++ /dev/null @@ -1,910 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function - -from collections import deque, OrderedDict -from hashlib import sha1 -import heapq -import itertools -import multiprocessing -import os -import re -import subprocess -import threading -import tempfile - -from rangelib import RangeSet - - -__all__ = ["EmptyImage", "DataImage", "BlockImageDiff"] - - -def compute_patch(src, tgt, imgdiff=False): - srcfd, srcfile = tempfile.mkstemp(prefix="src-") - tgtfd, tgtfile = tempfile.mkstemp(prefix="tgt-") - patchfd, patchfile = tempfile.mkstemp(prefix="patch-") - os.close(patchfd) - - try: - with os.fdopen(srcfd, "wb") as f_src: - for p in src: - f_src.write(p) - - with os.fdopen(tgtfd, "wb") as f_tgt: - for p in tgt: - f_tgt.write(p) - try: - os.unlink(patchfile) - except OSError: - pass - if imgdiff: - p = subprocess.call(["imgdiff", "-z", srcfile, tgtfile, patchfile], - stdout=open("/dev/null", "a"), - stderr=subprocess.STDOUT) - else: - p = subprocess.call(["bsdiff", srcfile, tgtfile, patchfile]) - - if p: - raise ValueError("diff failed: " + str(p)) - - with open(patchfile, "rb") as f: - return f.read() - finally: - try: - os.unlink(srcfile) - os.unlink(tgtfile) - os.unlink(patchfile) - except OSError: - pass - - -class Image(object): - def ReadRangeSet(self, ranges): - raise NotImplementedError - - def TotalSha1(self, include_clobbered_blocks=False): - raise NotImplementedError - - -class EmptyImage(Image): - """A zero-length image.""" - blocksize = 4096 - care_map = RangeSet() - clobbered_blocks = RangeSet() - extended = RangeSet() - total_blocks = 0 - file_map = {} - def ReadRangeSet(self, ranges): - return () - def TotalSha1(self, include_clobbered_blocks=False): - # EmptyImage always carries empty clobbered_blocks, so - # include_clobbered_blocks can be ignored. - assert self.clobbered_blocks.size() == 0 - return sha1().hexdigest() - - -class DataImage(Image): - """An image wrapped around a single string of data.""" - - def __init__(self, data, trim=False, pad=False): - self.data = data - self.blocksize = 4096 - - assert not (trim and pad) - - partial = len(self.data) % self.blocksize - if partial > 0: - if trim: - self.data = self.data[:-partial] - elif pad: - self.data += '\0' * (self.blocksize - partial) - else: - raise ValueError(("data for DataImage must be multiple of %d bytes " - "unless trim or pad is specified") % - (self.blocksize,)) - - assert len(self.data) % self.blocksize == 0 - - self.total_blocks = len(self.data) / self.blocksize - self.care_map = RangeSet(data=(0, self.total_blocks)) - self.clobbered_blocks = RangeSet() - self.extended = RangeSet() - - zero_blocks = [] - nonzero_blocks = [] - reference = '\0' * self.blocksize - - for i in range(self.total_blocks): - d = self.data[i*self.blocksize : (i+1)*self.blocksize] - if d == reference: - zero_blocks.append(i) - zero_blocks.append(i+1) - else: - nonzero_blocks.append(i) - nonzero_blocks.append(i+1) - - self.file_map = {"__ZERO": RangeSet(zero_blocks), - "__NONZERO": RangeSet(nonzero_blocks)} - - def ReadRangeSet(self, ranges): - return [self.data[s*self.blocksize:e*self.blocksize] for (s, e) in ranges] - - def TotalSha1(self, include_clobbered_blocks=False): - # DataImage always carries empty clobbered_blocks, so - # include_clobbered_blocks can be ignored. - assert self.clobbered_blocks.size() == 0 - return sha1(self.data).hexdigest() - - -class Transfer(object): - def __init__(self, tgt_name, src_name, tgt_ranges, src_ranges, style, by_id): - self.tgt_name = tgt_name - self.src_name = src_name - self.tgt_ranges = tgt_ranges - self.src_ranges = src_ranges - self.style = style - self.intact = (getattr(tgt_ranges, "monotonic", False) and - getattr(src_ranges, "monotonic", False)) - - # We use OrderedDict rather than dict so that the output is repeatable; - # otherwise it would depend on the hash values of the Transfer objects. - self.goes_before = OrderedDict() - self.goes_after = OrderedDict() - - self.stash_before = [] - self.use_stash = [] - - self.id = len(by_id) - by_id.append(self) - - def NetStashChange(self): - return (sum(sr.size() for (_, sr) in self.stash_before) - - sum(sr.size() for (_, sr) in self.use_stash)) - - def __str__(self): - return (str(self.id) + ": <" + str(self.src_ranges) + " " + self.style + - " to " + str(self.tgt_ranges) + ">") - - -# BlockImageDiff works on two image objects. An image object is -# anything that provides the following attributes: -# -# blocksize: the size in bytes of a block, currently must be 4096. -# -# total_blocks: the total size of the partition/image, in blocks. -# -# care_map: a RangeSet containing which blocks (in the range [0, -# total_blocks) we actually care about; i.e. which blocks contain -# data. -# -# file_map: a dict that partitions the blocks contained in care_map -# into smaller domains that are useful for doing diffs on. -# (Typically a domain is a file, and the key in file_map is the -# pathname.) -# -# clobbered_blocks: a RangeSet containing which blocks contain data -# but may be altered by the FS. They need to be excluded when -# verifying the partition integrity. -# -# ReadRangeSet(): a function that takes a RangeSet and returns the -# data contained in the image blocks of that RangeSet. The data -# is returned as a list or tuple of strings; concatenating the -# elements together should produce the requested data. -# Implementations are free to break up the data into list/tuple -# elements in any way that is convenient. -# -# TotalSha1(): a function that returns (as a hex string) the SHA-1 -# hash of all the data in the image (ie, all the blocks in the -# care_map minus clobbered_blocks, or including the clobbered -# blocks if include_clobbered_blocks is True). -# -# When creating a BlockImageDiff, the src image may be None, in which -# case the list of transfers produced will never read from the -# original image. - -class BlockImageDiff(object): - def __init__(self, tgt, src=None, threads=None, version=3): - if threads is None: - threads = multiprocessing.cpu_count() // 2 - if threads == 0: - threads = 1 - self.threads = threads - self.version = version - self.transfers = [] - self.src_basenames = {} - self.src_numpatterns = {} - - assert version in (1, 2, 3) - - self.tgt = tgt - if src is None: - src = EmptyImage() - self.src = src - - # The updater code that installs the patch always uses 4k blocks. - assert tgt.blocksize == 4096 - assert src.blocksize == 4096 - - # The range sets in each filemap should comprise a partition of - # the care map. - self.AssertPartition(src.care_map, src.file_map.values()) - self.AssertPartition(tgt.care_map, tgt.file_map.values()) - - def Compute(self, prefix): - # When looking for a source file to use as the diff input for a - # target file, we try: - # 1) an exact path match if available, otherwise - # 2) a exact basename match if available, otherwise - # 3) a basename match after all runs of digits are replaced by - # "#" if available, otherwise - # 4) we have no source for this target. - self.AbbreviateSourceNames() - self.FindTransfers() - - # Find the ordering dependencies among transfers (this is O(n^2) - # in the number of transfers). - self.GenerateDigraph() - # Find a sequence of transfers that satisfies as many ordering - # dependencies as possible (heuristically). - self.FindVertexSequence() - # Fix up the ordering dependencies that the sequence didn't - # satisfy. - if self.version == 1: - self.RemoveBackwardEdges() - else: - self.ReverseBackwardEdges() - self.ImproveVertexSequence() - - # Double-check our work. - self.AssertSequenceGood() - - self.ComputePatches(prefix) - self.WriteTransfers(prefix) - - def HashBlocks(self, source, ranges): # pylint: disable=no-self-use - data = source.ReadRangeSet(ranges) - ctx = sha1() - - for p in data: - ctx.update(p) - - return ctx.hexdigest() - - def WriteTransfers(self, prefix): - out = [] - - total = 0 - performs_read = False - - stashes = {} - stashed_blocks = 0 - max_stashed_blocks = 0 - - free_stash_ids = [] - next_stash_id = 0 - - for xf in self.transfers: - - if self.version < 2: - assert not xf.stash_before - assert not xf.use_stash - - for s, sr in xf.stash_before: - assert s not in stashes - if free_stash_ids: - sid = heapq.heappop(free_stash_ids) - else: - sid = next_stash_id - next_stash_id += 1 - stashes[s] = sid - stashed_blocks += sr.size() - if self.version == 2: - out.append("stash %d %s\n" % (sid, sr.to_string_raw())) - else: - sh = self.HashBlocks(self.src, sr) - if sh in stashes: - stashes[sh] += 1 - else: - stashes[sh] = 1 - out.append("stash %s %s\n" % (sh, sr.to_string_raw())) - - if stashed_blocks > max_stashed_blocks: - max_stashed_blocks = stashed_blocks - - free_string = [] - - if self.version == 1: - src_str = xf.src_ranges.to_string_raw() - elif self.version >= 2: - - # <# blocks> - # OR - # <# blocks> - # OR - # <# blocks> - - - size = xf.src_ranges.size() - src_str = [str(size)] - - unstashed_src_ranges = xf.src_ranges - mapped_stashes = [] - for s, sr in xf.use_stash: - sid = stashes.pop(s) - stashed_blocks -= sr.size() - unstashed_src_ranges = unstashed_src_ranges.subtract(sr) - sh = self.HashBlocks(self.src, sr) - sr = xf.src_ranges.map_within(sr) - mapped_stashes.append(sr) - if self.version == 2: - src_str.append("%d:%s" % (sid, sr.to_string_raw())) - else: - assert sh in stashes - src_str.append("%s:%s" % (sh, sr.to_string_raw())) - stashes[sh] -= 1 - if stashes[sh] == 0: - free_string.append("free %s\n" % (sh)) - stashes.pop(sh) - heapq.heappush(free_stash_ids, sid) - - if unstashed_src_ranges: - src_str.insert(1, unstashed_src_ranges.to_string_raw()) - if xf.use_stash: - mapped_unstashed = xf.src_ranges.map_within(unstashed_src_ranges) - src_str.insert(2, mapped_unstashed.to_string_raw()) - mapped_stashes.append(mapped_unstashed) - self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) - else: - src_str.insert(1, "-") - self.AssertPartition(RangeSet(data=(0, size)), mapped_stashes) - - src_str = " ".join(src_str) - - # all versions: - # zero - # new - # erase - # - # version 1: - # bsdiff patchstart patchlen - # imgdiff patchstart patchlen - # move - # - # version 2: - # bsdiff patchstart patchlen - # imgdiff patchstart patchlen - # move - # - # version 3: - # bsdiff patchstart patchlen srchash tgthash - # imgdiff patchstart patchlen srchash tgthash - # move hash - - tgt_size = xf.tgt_ranges.size() - - if xf.style == "new": - assert xf.tgt_ranges - out.append("%s %s\n" % (xf.style, xf.tgt_ranges.to_string_raw())) - total += tgt_size - elif xf.style == "move": - performs_read = True - assert xf.tgt_ranges - assert xf.src_ranges.size() == tgt_size - if xf.src_ranges != xf.tgt_ranges: - if self.version == 1: - out.append("%s %s %s\n" % ( - xf.style, - xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw())) - elif self.version == 2: - out.append("%s %s %s\n" % ( - xf.style, - xf.tgt_ranges.to_string_raw(), src_str)) - elif self.version >= 3: - # take into account automatic stashing of overlapping blocks - if xf.src_ranges.overlaps(xf.tgt_ranges): - temp_stash_usage = stashed_blocks + xf.src_ranges.size() - if temp_stash_usage > max_stashed_blocks: - max_stashed_blocks = temp_stash_usage - - out.append("%s %s %s %s\n" % ( - xf.style, - self.HashBlocks(self.tgt, xf.tgt_ranges), - xf.tgt_ranges.to_string_raw(), src_str)) - total += tgt_size - elif xf.style in ("bsdiff", "imgdiff"): - performs_read = True - assert xf.tgt_ranges - assert xf.src_ranges - if self.version == 1: - out.append("%s %d %d %s %s\n" % ( - xf.style, xf.patch_start, xf.patch_len, - xf.src_ranges.to_string_raw(), xf.tgt_ranges.to_string_raw())) - elif self.version == 2: - out.append("%s %d %d %s %s\n" % ( - xf.style, xf.patch_start, xf.patch_len, - xf.tgt_ranges.to_string_raw(), src_str)) - elif self.version >= 3: - # take into account automatic stashing of overlapping blocks - if xf.src_ranges.overlaps(xf.tgt_ranges): - temp_stash_usage = stashed_blocks + xf.src_ranges.size() - if temp_stash_usage > max_stashed_blocks: - max_stashed_blocks = temp_stash_usage - - out.append("%s %d %d %s %s %s %s\n" % ( - xf.style, - xf.patch_start, xf.patch_len, - self.HashBlocks(self.src, xf.src_ranges), - self.HashBlocks(self.tgt, xf.tgt_ranges), - xf.tgt_ranges.to_string_raw(), src_str)) - total += tgt_size - elif xf.style == "zero": - assert xf.tgt_ranges - to_zero = xf.tgt_ranges.subtract(xf.src_ranges) - if to_zero: - out.append("%s %s\n" % (xf.style, to_zero.to_string_raw())) - total += to_zero.size() - else: - raise ValueError("unknown transfer style '%s'\n" % xf.style) - - if free_string: - out.append("".join(free_string)) - - # sanity check: abort if we're going to need more than 512 MB if - # stash space - assert max_stashed_blocks * self.tgt.blocksize < (512 << 20) - - # Zero out extended blocks as a workaround for bug 20881595. - if self.tgt.extended: - out.append("zero %s\n" % (self.tgt.extended.to_string_raw(),)) - - # We erase all the blocks on the partition that a) don't contain useful - # data in the new image and b) will not be touched by dm-verity. - all_tgt = RangeSet(data=(0, self.tgt.total_blocks)) - all_tgt_minus_extended = all_tgt.subtract(self.tgt.extended) - new_dontcare = all_tgt_minus_extended.subtract(self.tgt.care_map) - if new_dontcare: - out.append("erase %s\n" % (new_dontcare.to_string_raw(),)) - - out.insert(0, "%d\n" % (self.version,)) # format version number - out.insert(1, str(total) + "\n") - if self.version >= 2: - # version 2 only: after the total block count, we give the number - # of stash slots needed, and the maximum size needed (in blocks) - out.insert(2, str(next_stash_id) + "\n") - out.insert(3, str(max_stashed_blocks) + "\n") - - with open(prefix + ".transfer.list", "wb") as f: - for i in out: - f.write(i) - - if self.version >= 2: - print("max stashed blocks: %d (%d bytes)\n" % ( - max_stashed_blocks, max_stashed_blocks * self.tgt.blocksize)) - - def ComputePatches(self, prefix): - print("Reticulating splines...") - diff_q = [] - patch_num = 0 - with open(prefix + ".new.dat", "wb") as new_f: - for xf in self.transfers: - if xf.style == "zero": - pass - elif xf.style == "new": - for piece in self.tgt.ReadRangeSet(xf.tgt_ranges): - new_f.write(piece) - elif xf.style == "diff": - src = self.src.ReadRangeSet(xf.src_ranges) - tgt = self.tgt.ReadRangeSet(xf.tgt_ranges) - - # We can't compare src and tgt directly because they may have - # the same content but be broken up into blocks differently, eg: - # - # ["he", "llo"] vs ["h", "ello"] - # - # We want those to compare equal, ideally without having to - # actually concatenate the strings (these may be tens of - # megabytes). - - src_sha1 = sha1() - for p in src: - src_sha1.update(p) - tgt_sha1 = sha1() - tgt_size = 0 - for p in tgt: - tgt_sha1.update(p) - tgt_size += len(p) - - if src_sha1.digest() == tgt_sha1.digest(): - # These are identical; we don't need to generate a patch, - # just issue copy commands on the device. - xf.style = "move" - else: - # For files in zip format (eg, APKs, JARs, etc.) we would - # like to use imgdiff -z if possible (because it usually - # produces significantly smaller patches than bsdiff). - # This is permissible if: - # - # - the source and target files are monotonic (ie, the - # data is stored with blocks in increasing order), and - # - we haven't removed any blocks from the source set. - # - # If these conditions are satisfied then appending all the - # blocks in the set together in order will produce a valid - # zip file (plus possibly extra zeros in the last block), - # which is what imgdiff needs to operate. (imgdiff is - # fine with extra zeros at the end of the file.) - imgdiff = (xf.intact and - xf.tgt_name.split(".")[-1].lower() - in ("apk", "jar", "zip")) - xf.style = "imgdiff" if imgdiff else "bsdiff" - diff_q.append((tgt_size, src, tgt, xf, patch_num)) - patch_num += 1 - - else: - assert False, "unknown style " + xf.style - - if diff_q: - if self.threads > 1: - print("Computing patches (using %d threads)..." % (self.threads,)) - else: - print("Computing patches...") - diff_q.sort() - - patches = [None] * patch_num - - # TODO: Rewrite with multiprocessing.ThreadPool? - lock = threading.Lock() - def diff_worker(): - while True: - with lock: - if not diff_q: - return - tgt_size, src, tgt, xf, patchnum = diff_q.pop() - patch = compute_patch(src, tgt, imgdiff=(xf.style == "imgdiff")) - size = len(patch) - with lock: - patches[patchnum] = (patch, xf) - print("%10d %10d (%6.2f%%) %7s %s" % ( - size, tgt_size, size * 100.0 / tgt_size, xf.style, - xf.tgt_name if xf.tgt_name == xf.src_name else ( - xf.tgt_name + " (from " + xf.src_name + ")"))) - - threads = [threading.Thread(target=diff_worker) - for _ in range(self.threads)] - for th in threads: - th.start() - while threads: - threads.pop().join() - else: - patches = [] - - p = 0 - with open(prefix + ".patch.dat", "wb") as patch_f: - for patch, xf in patches: - xf.patch_start = p - xf.patch_len = len(patch) - patch_f.write(patch) - p += len(patch) - - def AssertSequenceGood(self): - # Simulate the sequences of transfers we will output, and check that: - # - we never read a block after writing it, and - # - we write every block we care about exactly once. - - # Start with no blocks having been touched yet. - touched = RangeSet() - - # Imagine processing the transfers in order. - for xf in self.transfers: - # Check that the input blocks for this transfer haven't yet been touched. - - x = xf.src_ranges - if self.version >= 2: - for _, sr in xf.use_stash: - x = x.subtract(sr) - - assert not touched.overlaps(x) - # Check that the output blocks for this transfer haven't yet been touched. - assert not touched.overlaps(xf.tgt_ranges) - # Touch all the blocks written by this transfer. - touched = touched.union(xf.tgt_ranges) - - # Check that we've written every target block. - assert touched == self.tgt.care_map - - def ImproveVertexSequence(self): - print("Improving vertex order...") - - # At this point our digraph is acyclic; we reversed any edges that - # were backwards in the heuristically-generated sequence. The - # previously-generated order is still acceptable, but we hope to - # find a better order that needs less memory for stashed data. - # Now we do a topological sort to generate a new vertex order, - # using a greedy algorithm to choose which vertex goes next - # whenever we have a choice. - - # Make a copy of the edge set; this copy will get destroyed by the - # algorithm. - for xf in self.transfers: - xf.incoming = xf.goes_after.copy() - xf.outgoing = xf.goes_before.copy() - - L = [] # the new vertex order - - # S is the set of sources in the remaining graph; we always choose - # the one that leaves the least amount of stashed data after it's - # executed. - S = [(u.NetStashChange(), u.order, u) for u in self.transfers - if not u.incoming] - heapq.heapify(S) - - while S: - _, _, xf = heapq.heappop(S) - L.append(xf) - for u in xf.outgoing: - del u.incoming[xf] - if not u.incoming: - heapq.heappush(S, (u.NetStashChange(), u.order, u)) - - # if this fails then our graph had a cycle. - assert len(L) == len(self.transfers) - - self.transfers = L - for i, xf in enumerate(L): - xf.order = i - - def RemoveBackwardEdges(self): - print("Removing backward edges...") - in_order = 0 - out_of_order = 0 - lost_source = 0 - - for xf in self.transfers: - lost = 0 - size = xf.src_ranges.size() - for u in xf.goes_before: - # xf should go before u - if xf.order < u.order: - # it does, hurray! - in_order += 1 - else: - # it doesn't, boo. trim the blocks that u writes from xf's - # source, so that xf can go after u. - out_of_order += 1 - assert xf.src_ranges.overlaps(u.tgt_ranges) - xf.src_ranges = xf.src_ranges.subtract(u.tgt_ranges) - xf.intact = False - - if xf.style == "diff" and not xf.src_ranges: - # nothing left to diff from; treat as new data - xf.style = "new" - - lost = size - xf.src_ranges.size() - lost_source += lost - - print((" %d/%d dependencies (%.2f%%) were violated; " - "%d source blocks removed.") % - (out_of_order, in_order + out_of_order, - (out_of_order * 100.0 / (in_order + out_of_order)) - if (in_order + out_of_order) else 0.0, - lost_source)) - - def ReverseBackwardEdges(self): - print("Reversing backward edges...") - in_order = 0 - out_of_order = 0 - stashes = 0 - stash_size = 0 - - for xf in self.transfers: - for u in xf.goes_before.copy(): - # xf should go before u - if xf.order < u.order: - # it does, hurray! - in_order += 1 - else: - # it doesn't, boo. modify u to stash the blocks that it - # writes that xf wants to read, and then require u to go - # before xf. - out_of_order += 1 - - overlap = xf.src_ranges.intersect(u.tgt_ranges) - assert overlap - - u.stash_before.append((stashes, overlap)) - xf.use_stash.append((stashes, overlap)) - stashes += 1 - stash_size += overlap.size() - - # reverse the edge direction; now xf must go after u - del xf.goes_before[u] - del u.goes_after[xf] - xf.goes_after[u] = None # value doesn't matter - u.goes_before[xf] = None - - print((" %d/%d dependencies (%.2f%%) were violated; " - "%d source blocks stashed.") % - (out_of_order, in_order + out_of_order, - (out_of_order * 100.0 / (in_order + out_of_order)) - if (in_order + out_of_order) else 0.0, - stash_size)) - - def FindVertexSequence(self): - print("Finding vertex sequence...") - - # This is based on "A Fast & Effective Heuristic for the Feedback - # Arc Set Problem" by P. Eades, X. Lin, and W.F. Smyth. Think of - # it as starting with the digraph G and moving all the vertices to - # be on a horizontal line in some order, trying to minimize the - # number of edges that end up pointing to the left. Left-pointing - # edges will get removed to turn the digraph into a DAG. In this - # case each edge has a weight which is the number of source blocks - # we'll lose if that edge is removed; we try to minimize the total - # weight rather than just the number of edges. - - # Make a copy of the edge set; this copy will get destroyed by the - # algorithm. - for xf in self.transfers: - xf.incoming = xf.goes_after.copy() - xf.outgoing = xf.goes_before.copy() - - # We use an OrderedDict instead of just a set so that the output - # is repeatable; otherwise it would depend on the hash values of - # the transfer objects. - G = OrderedDict() - for xf in self.transfers: - G[xf] = None - s1 = deque() # the left side of the sequence, built from left to right - s2 = deque() # the right side of the sequence, built from right to left - - while G: - - # Put all sinks at the end of the sequence. - while True: - sinks = [u for u in G if not u.outgoing] - if not sinks: - break - for u in sinks: - s2.appendleft(u) - del G[u] - for iu in u.incoming: - del iu.outgoing[u] - - # Put all the sources at the beginning of the sequence. - while True: - sources = [u for u in G if not u.incoming] - if not sources: - break - for u in sources: - s1.append(u) - del G[u] - for iu in u.outgoing: - del iu.incoming[u] - - if not G: - break - - # Find the "best" vertex to put next. "Best" is the one that - # maximizes the net difference in source blocks saved we get by - # pretending it's a source rather than a sink. - - max_d = None - best_u = None - for u in G: - d = sum(u.outgoing.values()) - sum(u.incoming.values()) - if best_u is None or d > max_d: - max_d = d - best_u = u - - u = best_u - s1.append(u) - del G[u] - for iu in u.outgoing: - del iu.incoming[u] - for iu in u.incoming: - del iu.outgoing[u] - - # Now record the sequence in the 'order' field of each transfer, - # and by rearranging self.transfers to be in the chosen sequence. - - new_transfers = [] - for x in itertools.chain(s1, s2): - x.order = len(new_transfers) - new_transfers.append(x) - del x.incoming - del x.outgoing - - self.transfers = new_transfers - - def GenerateDigraph(self): - print("Generating digraph...") - for a in self.transfers: - for b in self.transfers: - if a is b: - continue - - # If the blocks written by A are read by B, then B needs to go before A. - i = a.tgt_ranges.intersect(b.src_ranges) - if i: - if b.src_name == "__ZERO": - # the cost of removing source blocks for the __ZERO domain - # is (nearly) zero. - size = 0 - else: - size = i.size() - b.goes_before[a] = size - a.goes_after[b] = size - - def FindTransfers(self): - empty = RangeSet() - for tgt_fn, tgt_ranges in self.tgt.file_map.items(): - if tgt_fn == "__ZERO": - # the special "__ZERO" domain is all the blocks not contained - # in any file and that are filled with zeros. We have a - # special transfer style for zero blocks. - src_ranges = self.src.file_map.get("__ZERO", empty) - Transfer(tgt_fn, "__ZERO", tgt_ranges, src_ranges, - "zero", self.transfers) - continue - - elif tgt_fn == "__COPY": - # "__COPY" domain includes all the blocks not contained in any - # file and that need to be copied unconditionally to the target. - Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) - continue - - elif tgt_fn in self.src.file_map: - # Look for an exact pathname match in the source. - Transfer(tgt_fn, tgt_fn, tgt_ranges, self.src.file_map[tgt_fn], - "diff", self.transfers) - continue - - b = os.path.basename(tgt_fn) - if b in self.src_basenames: - # Look for an exact basename match in the source. - src_fn = self.src_basenames[b] - Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn], - "diff", self.transfers) - continue - - b = re.sub("[0-9]+", "#", b) - if b in self.src_numpatterns: - # Look for a 'number pattern' match (a basename match after - # all runs of digits are replaced by "#"). (This is useful - # for .so files that contain version numbers in the filename - # that get bumped.) - src_fn = self.src_numpatterns[b] - Transfer(tgt_fn, src_fn, tgt_ranges, self.src.file_map[src_fn], - "diff", self.transfers) - continue - - Transfer(tgt_fn, None, tgt_ranges, empty, "new", self.transfers) - - def AbbreviateSourceNames(self): - for k in self.src.file_map.keys(): - b = os.path.basename(k) - self.src_basenames[b] = k - b = re.sub("[0-9]+", "#", b) - self.src_numpatterns[b] = k - - @staticmethod - def AssertPartition(total, seq): - """Assert that all the RangeSets in 'seq' form a partition of the - 'total' RangeSet (ie, they are nonintersecting and their union - equals 'total').""" - so_far = RangeSet() - for i in seq: - assert not so_far.overlaps(i) - so_far = so_far.union(i) - assert so_far == total diff --git a/linux-x86/bsdiff b/releasetools/bsdiff similarity index 100% rename from linux-x86/bsdiff rename to releasetools/bsdiff diff --git a/releasetools/common.py b/releasetools/common.py index f6eae50..d3778dc 100644 --- a/releasetools/common.py +++ b/releasetools/common.py @@ -20,7 +20,6 @@ import os import platform import re -import shlex import shutil import subprocess import sys @@ -29,43 +28,30 @@ import time import zipfile -import blockimgdiff -import rangelib - -from hashlib import sha1 as sha1 - - -class Options(object): - def __init__(self): - self.search_path = os.path.join(os.environ["PORT_ROOT"], "tools"); - self.signapk_path = "signapk.jar" # Relative to search_path - self.extra_signapk_args = [] - self.java_path = "java" # Use the one on the path by default. - self.java_args = "-Xmx2048m" # JVM Args - self.public_key_suffix = ".x509.pem" - self.private_key_suffix = ".pk8" - # use otatools built boot_signer by default - self.boot_signer_path = "boot_signer" - self.boot_signer_args = [] - self.verity_signer_path = None - self.verity_signer_args = [] - self.verbose = False - self.tempfiles = [] - self.device_specific = None - self.extras = {} - self.info_dict = None - self.worker_threads = None +try: + from hashlib import sha1 as sha1 +except ImportError: + from sha import sha as sha1 +# missing in Python 2.4 and before +if not hasattr(os, "SEEK_SET"): + os.SEEK_SET = 0 +class Options(object): pass OPTIONS = Options() +OPTIONS.search_path = os.path.join(os.environ["PORT_ROOT"], "tools"); +OPTIONS.verbose = False +OPTIONS.tempfiles = [] +OPTIONS.device_specific = None +OPTIONS.extras = {} +OPTIONS.info_dict = None # Values for "certificate" in apkcerts that mean special things. SPECIAL_CERT_STRINGS = ("PRESIGNED", "EXTERNAL") -class ExternalError(RuntimeError): - pass +class ExternalError(RuntimeError): pass def Run(args, **kwargs): @@ -92,24 +78,17 @@ def CloseInheritedPipes(): pass -def LoadInfoDict(input_file): +def LoadInfoDict(zip): """Read and parse the META/misc_info.txt key/value pairs from the input target files and return a dict.""" - def read_helper(fn): - if isinstance(input_file, zipfile.ZipFile): - return input_file.read(fn) - else: - path = os.path.join(input_file, *fn.split("/")) - try: - with open(path) as f: - return f.read() - except IOError as e: - if e.errno == errno.ENOENT: - raise KeyError(fn) d = {} try: - d = LoadDictionaryFromLines(read_helper("META/misc_info.txt").split("\n")) + for line in zip.read("META/misc_info.txt").split("\n"): + line = line.strip() + if not line or line.startswith("#"): continue + k, v = line.split("=", 1) + d[k] = v except KeyError: # ok if misc_info.txt doesn't exist pass @@ -120,37 +99,30 @@ def read_helper(fn): if "mkyaffs2_extra_flags" not in d: try: - d["mkyaffs2_extra_flags"] = read_helper( - "META/mkyaffs2-extra-flags.txt").strip() + d["mkyaffs2_extra_flags"] = zip.read("META/mkyaffs2-extra-flags.txt").strip() except KeyError: # ok if flags don't exist pass if "recovery_api_version" not in d: try: - d["recovery_api_version"] = read_helper( - "META/recovery-api-version.txt").strip() + d["recovery_api_version"] = zip.read("META/recovery-api-version.txt").strip() except KeyError: raise ValueError("can't find recovery API version in input target-files") if "tool_extensions" not in d: try: - d["tool_extensions"] = read_helper("META/tool-extensions.txt").strip() + d["tool_extensions"] = zip.read("META/tool-extensions.txt").strip() except KeyError: # ok if extensions don't exist pass - if "fstab_version" not in d: - d["fstab_version"] = "1" - try: - data = read_helper("META/imagesizes.txt") + data = zip.read("META/imagesizes.txt") for line in data.split("\n"): - if not line: - continue + if not line: continue name, value = line.split(" ", 1) - if not value: - continue + if not value: continue if name == "blocksize": d[name] = value else: @@ -165,129 +137,57 @@ def makeint(key): makeint("recovery_api_version") makeint("blocksize") makeint("system_size") - makeint("vendor_size") makeint("userdata_size") - makeint("cache_size") - makeint("cust_size") makeint("recovery_size") makeint("boot_size") - makeint("fstab_version") - d["fstab"] = LoadRecoveryFSTab(read_helper, d["fstab_version"]) - d["build.prop"] = LoadBuildProp(read_helper) - return d - -def LoadBuildProp(read_helper): - try: - data = read_helper("SYSTEM/build.prop") - except KeyError: - print "Warning: could not find SYSTEM/build.prop in %s" % zip - data = "" - return LoadDictionaryFromLines(data.split("\n")) - -def LoadDictionaryFromLines(lines): - d = {} - for line in lines: - line = line.strip() - if not line or line.startswith("#"): - continue - if "=" in line: - name, value = line.split("=", 1) - d[name] = value + d["fstab"] = LoadRecoveryFSTab(zip) return d -def LoadRecoveryFSTab(read_helper, fstab_version): +def LoadRecoveryFSTab(zip): class Partition(object): - def __init__(self, mount_point, fs_type, device, length, device2, context): - self.mount_point = mount_point - self.fs_type = fs_type - self.device = device - self.length = length - self.device2 = device2 - self.context = context + pass try: - data = read_helper("RECOVERY/RAMDISK/etc/recovery.fstab") + data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab") except KeyError: - print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab" + print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab in %s." % zip data = "" - if fstab_version == 1: - d = {} - for line in data.split("\n"): - line = line.strip() - if not line or line.startswith("#"): - continue - pieces = line.split() - if not 3 <= len(pieces) <= 4: - raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) - options = None - if len(pieces) >= 4: - if pieces[3].startswith("/"): - device2 = pieces[3] - if len(pieces) >= 5: - options = pieces[4] - else: - device2 = None - options = pieces[3] + d = {} + for line in data.split("\n"): + line = line.strip() + if not line or line.startswith("#"): continue + pieces = line.split() + if not (3 <= len(pieces) <= 4): + raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) + + p = Partition() + p.mount_point = pieces[0] + p.fs_type = pieces[1] + p.device = pieces[2] + p.length = 0 + options = None + if len(pieces) >= 4: + if pieces[3].startswith("/"): + p.device2 = pieces[3] + if len(pieces) >= 5: + options = pieces[4] else: - device2 = None - - mount_point = pieces[0] - length = 0 - if options: - options = options.split(",") - for i in options: - if i.startswith("length="): - length = int(i[7:]) - else: - print "%s: unknown option \"%s\"" % (mount_point, i) - - d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[1], - device=pieces[2], length=length, - device2=device2, context=None) - - elif fstab_version == 2: - d = {} - for line in data.split("\n"): - line = line.strip() - if not line or line.startswith("#"): - continue - # - pieces = line.split() - if len(pieces) != 5: - raise ValueError("malformed recovery.fstab line: \"%s\"" % (line,)) - - # Ignore entries that are managed by vold - options = pieces[4] - if "voldmanaged=" in options: - continue - - # It's a good line, parse it - length = 0 + p.device2 = None + options = pieces[3] + else: + p.device2 = None + + if options: options = options.split(",") for i in options: if i.startswith("length="): - length = int(i[7:]) + p.length = int(i[7:]) else: - # Ignore all unknown options in the unified fstab - continue - - mount_flags = pieces[3] - # Honor the SELinux context if present. - context = None - for i in mount_flags.split(","): - if i.startswith("context="): - context = i - - mount_point = pieces[1] - d[mount_point] = Partition(mount_point=mount_point, fs_type=pieces[2], - device=pieces[0], length=length, - device2=None, context=context) - - else: - raise ValueError("Unknown fstab_version: \"%d\"" % (fstab_version,)) + print "%s: unknown option \"%s\"" % (p.mount_point, i) + d[p.mount_point] = p return d @@ -295,8 +195,7 @@ def DumpInfoDict(d): for k, v in sorted(d.items()): print "%-25s = (%s) %s" % (k, type(v).__name__, v) - -def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): +def BuildBootableImage(sourcedir): """Take a kernel, cmdline, and ramdisk directory from the input (in 'sourcedir'), and turn them into a boot image. Return the image data, or None if sourcedir does not appear to contains files for @@ -306,34 +205,20 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): not os.access(os.path.join(sourcedir, "kernel"), os.F_OK)): return None - if info_dict is None: - info_dict = OPTIONS.info_dict - ramdisk_img = tempfile.NamedTemporaryFile() img = tempfile.NamedTemporaryFile() - if os.access(fs_config_file, os.F_OK): - cmd = ["mkbootfs", "-f", fs_config_file, os.path.join(sourcedir, "RAMDISK")] - else: - cmd = ["mkbootfs", os.path.join(sourcedir, "RAMDISK")] - p1 = Run(cmd, stdout=subprocess.PIPE) + p1 = Run(["mkbootfs", os.path.join(sourcedir, "RAMDISK")], + stdout=subprocess.PIPE) p2 = Run(["minigzip"], stdin=p1.stdout, stdout=ramdisk_img.file.fileno()) p2.wait() p1.wait() - assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (sourcedir,) - assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (sourcedir,) - - # use MKBOOTIMG from environ, or "mkbootimg" if empty or not set - mkbootimg = os.getenv('MKBOOTIMG') or "mkbootimg" + assert p1.returncode == 0, "mkbootfs of %s ramdisk failed" % (targetname,) + assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (targetname,) - cmd = [mkbootimg, "--kernel", os.path.join(sourcedir, "kernel")] - - fn = os.path.join(sourcedir, "second") - if os.access(fn, os.F_OK): - cmd.append("--second") - cmd.append(fn) + cmd = ["mkbootimg", "--kernel", os.path.join(sourcedir, "kernel")] fn = os.path.join(sourcedir, "cmdline") if os.access(fn, os.F_OK): @@ -350,52 +235,14 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): cmd.append("--pagesize") cmd.append(open(fn).read().rstrip("\n")) - args = info_dict.get("mkbootimg_args", None) - if args and args.strip(): - cmd.extend(shlex.split(args)) - - img_unsigned = None - if info_dict.get("vboot", None): - img_unsigned = tempfile.NamedTemporaryFile() - cmd.extend(["--ramdisk", ramdisk_img.name, - "--output", img_unsigned.name]) - else: - cmd.extend(["--ramdisk", ramdisk_img.name, - "--output", img.name]) + cmd.extend(["--ramdisk", ramdisk_img.name, + "--output", img.name]) p = Run(cmd, stdout=subprocess.PIPE) p.communicate() assert p.returncode == 0, "mkbootimg of %s image failed" % ( os.path.basename(sourcedir),) - if (info_dict.get("boot_signer", None) == "true" and - info_dict.get("verity_key", None)): - path = "/" + os.path.basename(sourcedir).lower() - cmd = [OPTIONS.boot_signer_path] - cmd.extend(OPTIONS.boot_signer_args) - cmd.extend([path, img.name, - info_dict["verity_key"] + ".pk8", - info_dict["verity_key"] + ".x509.pem", img.name]) - p = Run(cmd, stdout=subprocess.PIPE) - p.communicate() - assert p.returncode == 0, "boot_signer of %s image failed" % path - - # Sign the image if vboot is non-empty. - elif info_dict.get("vboot", None): - path = "/" + os.path.basename(sourcedir).lower() - img_keyblock = tempfile.NamedTemporaryFile() - cmd = [info_dict["vboot_signer_cmd"], info_dict["futility"], - img_unsigned.name, info_dict["vboot_key"] + ".vbpubk", - info_dict["vboot_key"] + ".vbprivk", img_keyblock.name, - img.name] - p = Run(cmd, stdout=subprocess.PIPE) - p.communicate() - assert p.returncode == 0, "vboot_signer of %s image failed" % path - - # Clean up the temp files. - img_unsigned.close() - img_keyblock.close() - img.seek(os.SEEK_SET, 0) data = img.read() @@ -405,32 +252,20 @@ def BuildBootableImage(sourcedir, fs_config_file, info_dict=None): return data -def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir, - info_dict=None): +def GetBootableImage(name, prebuilt_name, unpack_dir, tree_subdir): """Return a File object (with name 'name') with the desired bootable image. Look for it in 'unpack_dir'/BOOTABLE_IMAGES under the name - 'prebuilt_name', otherwise look for it under 'unpack_dir'/IMAGES, - otherwise construct it from the source files in + 'prebuilt_name', otherwise construct it from the source files in 'unpack_dir'/'tree_subdir'.""" prebuilt_path = os.path.join(unpack_dir, "BOOTABLE_IMAGES", prebuilt_name) if os.path.exists(prebuilt_path): - print "using prebuilt %s from BOOTABLE_IMAGES..." % (prebuilt_name,) - return File.FromLocalFile(name, prebuilt_path) - - prebuilt_path = os.path.join(unpack_dir, "IMAGES", prebuilt_name) - if os.path.exists(prebuilt_path): - print "using prebuilt %s from IMAGES..." % (prebuilt_name,) + print "using prebuilt %s..." % (prebuilt_name,) return File.FromLocalFile(name, prebuilt_path) - - print "building image from target_files %s..." % (tree_subdir,) - fs_config = "META/" + tree_subdir.lower() + "_filesystem_config.txt" - data = BuildBootableImage(os.path.join(unpack_dir, tree_subdir), - os.path.join(unpack_dir, fs_config), - info_dict) - if data: - return File(name, data) - return None + else: + return None + #print "building image from target_files %s..." % (tree_subdir,) + #return File(name, BuildBootableImage(os.path.join(unpack_dir, tree_subdir))) def UnzipTemp(filename, pattern=None): @@ -474,7 +309,6 @@ def GetKeyPasswords(keylist): no_passwords = [] need_passwords = [] - key_passwords = {} devnull = open("/dev/null", "w+b") for k in sorted(keylist): # We don't need a password for things that aren't really keys. @@ -482,36 +316,19 @@ def GetKeyPasswords(keylist): no_passwords.append(k) continue - p = Run(["openssl", "pkcs8", "-in", k+OPTIONS.private_key_suffix, + p = Run(["openssl", "pkcs8", "-in", k+".pk8", "-inform", "DER", "-nocrypt"], stdin=devnull.fileno(), stdout=devnull.fileno(), stderr=subprocess.STDOUT) p.communicate() if p.returncode == 0: - # Definitely an unencrypted key. no_passwords.append(k) else: - p = Run(["openssl", "pkcs8", "-in", k+OPTIONS.private_key_suffix, - "-inform", "DER", "-passin", "pass:"], - stdin=devnull.fileno(), - stdout=devnull.fileno(), - stderr=subprocess.PIPE) - _, stderr = p.communicate() - if p.returncode == 0: - # Encrypted key with empty string as password. - key_passwords[k] = '' - elif stderr.startswith('Error decrypting key'): - # Definitely encrypted key. - # It would have said "Error reading key" if it didn't parse correctly. - need_passwords.append(k) - else: - # Potentially, a type of key that openssl doesn't understand. - # We'll let the routines in signapk.jar handle it. - no_passwords.append(k) + need_passwords.append(k) devnull.close() - key_passwords.update(PasswordManager().GetPasswords(need_passwords)) + key_passwords = PasswordManager().GetPasswords(need_passwords) key_passwords.update(dict.fromkeys(no_passwords, None)) return key_passwords @@ -539,13 +356,11 @@ def SignFile(input_name, output_name, key, password, align=None, else: sign_name = output_name - cmd = [OPTIONS.java_path, OPTIONS.java_args, "-jar", - os.path.join(OPTIONS.search_path, OPTIONS.signapk_path)] - cmd.extend(OPTIONS.extra_signapk_args) + cmd = ["java", "-Xmx4096m", "-jar", + os.path.join(OPTIONS.search_path, "signapk.jar")] if whole_file: cmd.append("-w") - cmd.extend([key + OPTIONS.public_key_suffix, - key + OPTIONS.private_key_suffix, + cmd.extend([key + ".x509.pem", key + ".pk8", input_name, sign_name]) p = Run(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) @@ -556,7 +371,7 @@ def SignFile(input_name, output_name, key, password, align=None, raise ExternalError("signapk.jar failed: return code %s" % (p.returncode,)) if align: - p = Run(["zipalign", "-f", "-p", str(align), sign_name, output_name]) + p = Run(["zipalign", "-f", str(align), sign_name, output_name]) p.communicate() if p.returncode != 0: raise ExternalError("zipalign failed: return code %s" % (p.returncode,)) @@ -568,39 +383,31 @@ def CheckSize(data, target, info_dict): any, for the given target. Raise exception if the data is too big. Print a warning if the data is nearing the maximum size.""" - if target.endswith(".img"): - target = target[:-4] + if target.endswith(".img"): target = target[:-4] mount_point = "/" + target - fs_type = None - limit = None if info_dict["fstab"]: - if mount_point == "/userdata": - mount_point = "/data" + if mount_point == "/userdata": mount_point = "/data" p = info_dict["fstab"][mount_point] fs_type = p.fs_type - device = p.device - if "/" in device: - device = device[device.rfind("/")+1:] - limit = info_dict.get(device + "_size", None) - if not fs_type or not limit: - return + limit = info_dict.get(p.device + "_size", None) + if not fs_type or not limit: return if fs_type == "yaffs2": # image size should be increased by 1/64th to account for the # spare area (64 bytes per 2k page) limit = limit / 2048 * (2048+64) - size = len(data) - pct = float(size) * 100.0 / limit - msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) - if pct >= 99.0: - raise ExternalError(msg) - elif pct >= 95.0: - print - print " WARNING: ", msg - print - elif OPTIONS.verbose: - print " ", msg + size = len(data) + pct = float(size) * 100.0 / limit + msg = "%s size (%d) is %.2f%% of limit (%d)" % (target, size, pct, limit) + if pct >= 99.0: + raise ExternalError(msg) + elif pct >= 95.0: + print + print " WARNING: ", msg + print + elif OPTIONS.verbose: + print " ", msg def ReadApkCerts(tf_zip): @@ -609,20 +416,17 @@ def ReadApkCerts(tf_zip): certmap = {} for line in tf_zip.read("META/apkcerts.txt").split("\n"): line = line.strip() - if not line: - continue + if not line: continue m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' r'private_key="(.*)"$', line) if m: name, cert, privkey = m.groups() - public_key_suffix_len = len(OPTIONS.public_key_suffix) - private_key_suffix_len = len(OPTIONS.private_key_suffix) if cert in SPECIAL_CERT_STRINGS and not privkey: certmap[name] = cert - elif (cert.endswith(OPTIONS.public_key_suffix) and - privkey.endswith(OPTIONS.private_key_suffix) and - cert[:-public_key_suffix_len] == privkey[:-private_key_suffix_len]): - certmap[name] = cert[:-public_key_suffix_len] + elif (cert.endswith(".x509.pem") and + privkey.endswith(".pk8") and + cert[:-9] == privkey[:-4]): + certmap[name] = cert[:-9] else: raise ValueError("failed to parse line from apkcerts.txt:\n" + line) return certmap @@ -666,17 +470,15 @@ def ParseOptions(argv, try: opts, args = getopt.getopt( argv, "hvp:s:x:" + extra_opts, - ["help", "verbose", "path=", "signapk_path=", "extra_signapk_args=", - "java_path=", "java_args=", "public_key_suffix=", - "private_key_suffix=", "boot_signer_path=", "boot_signer_args=", - "verity_signer_path=", "verity_signer_args=", "device_specific=", - "extra="] + - list(extra_long_opts)) - except getopt.GetoptError as err: + ["help", "verbose", "path=", "device_specific=", "extra="] + + list(extra_long_opts)) + except getopt.GetoptError, err: Usage(docstring) print "**", str(err), "**" sys.exit(2) + path_specified = False + for o, a in opts: if o in ("-h", "--help"): Usage(docstring) @@ -685,26 +487,6 @@ def ParseOptions(argv, OPTIONS.verbose = True elif o in ("-p", "--path"): OPTIONS.search_path = a - elif o in ("--signapk_path",): - OPTIONS.signapk_path = a - elif o in ("--extra_signapk_args",): - OPTIONS.extra_signapk_args = shlex.split(a) - elif o in ("--java_path",): - OPTIONS.java_path = a - elif o in ("--java_args",): - OPTIONS.java_args = a - elif o in ("--public_key_suffix",): - OPTIONS.public_key_suffix = a - elif o in ("--private_key_suffix",): - OPTIONS.private_key_suffix = a - elif o in ("--boot_signer_path",): - OPTIONS.boot_signer_path = a - elif o in ("--boot_signer_args",): - OPTIONS.boot_signer_args = shlex.split(a) - elif o in ("--verity_signer_path",): - OPTIONS.verity_signer_path = a - elif o in ("--verity_signer_args",): - OPTIONS.verity_signer_args = shlex.split(a) elif o in ("-s", "--device_specific"): OPTIONS.device_specific = a elif o in ("-x", "--extra"): @@ -714,22 +496,12 @@ def ParseOptions(argv, if extra_option_handler is None or not extra_option_handler(o, a): assert False, "unknown option \"%s\"" % (o,) - if OPTIONS.search_path: - os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") + - os.pathsep + os.environ["PATH"]) + os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") + + os.pathsep + os.environ["PATH"]) return args -def MakeTempFile(prefix=None, suffix=None): - """Make a temp file and add it to the list of things to be deleted - when Cleanup() is called. Return the filename.""" - fd, fn = tempfile.mkstemp(prefix=prefix, suffix=suffix) - os.close(fd) - OPTIONS.tempfiles.append(fn) - return fn - - def Cleanup(): for i in OPTIONS.tempfiles: if os.path.isdir(i): @@ -763,8 +535,7 @@ def GetPasswords(self, items): if i not in current or not current[i]: missing.append(i) # Are all the passwords already in the file? - if not missing: - return current + if not missing: return current for i in missing: current[i] = "" @@ -778,7 +549,7 @@ def GetPasswords(self, items): current = self.UpdateAndReadFile(current) - def PromptResult(self, current): # pylint: disable=no-self-use + def PromptResult(self, current): """Prompt the user to enter a value (password) for each key in 'current' whose value is fales. Returns a new dict with all the values. @@ -789,10 +560,9 @@ def PromptResult(self, current): # pylint: disable=no-self-use result[k] = v else: while True: - result[k] = getpass.getpass( - "Enter password for %s key> " % k).strip() - if result[k]: - break + result[k] = getpass.getpass("Enter password for %s key> " + % (k,)).strip() + if result[k]: break return result def UpdateAndReadFile(self, current): @@ -800,13 +570,14 @@ def UpdateAndReadFile(self, current): return self.PromptResult(current) f = open(self.pwfile, "w") - os.chmod(self.pwfile, 0o600) + os.chmod(self.pwfile, 0600) f.write("# Enter key passwords between the [[[ ]]] brackets.\n") f.write("# (Additional spaces are harmless.)\n\n") first_line = None - sorted_list = sorted([(not v, k, v) for (k, v) in current.iteritems()]) - for i, (_, k, v) in enumerate(sorted_list): + sorted = [(not v, k, v) for (k, v) in current.iteritems()] + sorted.sort() + for i, (_, k, v) in enumerate(sorted): f.write("[[[ %s ]]] %s\n" % (v, k)) if not v and first_line is None: # position cursor on first line with no password. @@ -820,122 +591,35 @@ def UpdateAndReadFile(self, current): def ReadFile(self): result = {} - if self.pwfile is None: - return result + if self.pwfile is None: return result try: f = open(self.pwfile, "r") for line in f: line = line.strip() - if not line or line[0] == '#': - continue + if not line or line[0] == '#': continue m = re.match(r"^\[\[\[\s*(.*?)\s*\]\]\]\s*(\S+)$", line) if not m: print "failed to parse password file: ", line else: result[m.group(2)] = m.group(1) f.close() - except IOError as e: + except IOError, e: if e.errno != errno.ENOENT: print "error reading password file: ", str(e) return result -def ZipWrite(zip_file, filename, arcname=None, perms=0o644, - compress_type=None): - import datetime - - # http://b/18015246 - # Python 2.7's zipfile implementation wrongly thinks that zip64 is required - # for files larger than 2GiB. We can work around this by adjusting their - # limit. Note that `zipfile.writestr()` will not work for strings larger than - # 2GiB. The Python interpreter sometimes rejects strings that large (though - # it isn't clear to me exactly what circumstances cause this). - # `zipfile.write()` must be used directly to work around this. - # - # This mess can be avoided if we port to python3. - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - if compress_type is None: - compress_type = zip_file.compression - if arcname is None: - arcname = filename - - saved_stat = os.stat(filename) - - try: - # `zipfile.write()` doesn't allow us to pass ZipInfo, so just modify the - # file to be zipped and reset it when we're done. - os.chmod(filename, perms) - - # Use a fixed timestamp so the output is repeatable. - epoch = datetime.datetime.fromtimestamp(0) - timestamp = (datetime.datetime(2009, 1, 1) - epoch).total_seconds() - os.utime(filename, (timestamp, timestamp)) - - zip_file.write(filename, arcname=arcname, compress_type=compress_type) - finally: - os.chmod(filename, saved_stat.st_mode) - os.utime(filename, (saved_stat.st_atime, saved_stat.st_mtime)) - zipfile.ZIP64_LIMIT = saved_zip64_limit - - -def ZipWriteStr(zip_file, zinfo_or_arcname, data, perms=None, - compress_type=None): - """Wrap zipfile.writestr() function to work around the zip64 limit. - - Even with the ZIP64_LIMIT workaround, it won't allow writing a string - longer than 2GiB. It gives 'OverflowError: size does not fit in an int' - when calling crc32(bytes). - - But it still works fine to write a shorter string into a large zip file. - We should use ZipWrite() whenever possible, and only use ZipWriteStr() - when we know the string won't be too long. - """ - - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - if not isinstance(zinfo_or_arcname, zipfile.ZipInfo): - zinfo = zipfile.ZipInfo(filename=zinfo_or_arcname) - zinfo.compress_type = zip_file.compression - if perms is None: - perms = 0o644 - else: - zinfo = zinfo_or_arcname - - # If compress_type is given, it overrides the value in zinfo. - if compress_type is not None: - zinfo.compress_type = compress_type - - # If perms is given, it has a priority. - if perms is not None: - zinfo.external_attr = perms << 16 - - # Use a fixed timestamp so the output is repeatable. - zinfo.date_time = (2009, 1, 1, 0, 0, 0) - - zip_file.writestr(zinfo, data) - zipfile.ZIP64_LIMIT = saved_zip64_limit - - -def ZipClose(zip_file): - # http://b/18015246 - # zipfile also refers to ZIP64_LIMIT during close() when it writes out the - # central directory. - saved_zip64_limit = zipfile.ZIP64_LIMIT - zipfile.ZIP64_LIMIT = (1 << 32) - 1 - - zip_file.close() - - zipfile.ZIP64_LIMIT = saved_zip64_limit +def ZipWriteStr(zip, filename, data, perms=0644): + # use a fixed timestamp so the output is repeatable. + zinfo = zipfile.ZipInfo(filename=filename, + date_time=(2009, 1, 1, 0, 0, 0)) + zinfo.compress_type = zip.compression + zinfo.external_attr = perms << 16 + zip.writestr(zinfo, data) class DeviceSpecificParams(object): module = None - # MIUI ADD: - miui_module = None - def __init__(self, **kwargs): """Keyword arguments to the constructor become attributes of this object, which is passed to all functions in the device-specific @@ -943,13 +627,10 @@ def __init__(self, **kwargs): for k, v in kwargs.iteritems(): setattr(self, k, v) self.extras = OPTIONS.extras - # MIUI ADD: - self._init_miui_module() if self.module is None: path = OPTIONS.device_specific - if not path: - return + if not path: return try: if os.path.isdir(path): info = imp.find_module("releasetools", [path]) @@ -959,44 +640,19 @@ def __init__(self, **kwargs): if x == ".py": f = b info = imp.find_module(f, [d]) - print "loaded device-specific extensions from", path self.module = imp.load_module("device_specific", *info) except ImportError: print "unable to load device-specific module; assuming none" - # MIUI ADD: - def _init_miui_module(self): - if self.miui_module is None: - miui_path = os.path.join(os.environ['PORT_ROOT'], "tools/releasetools") - if not miui_path: return - try: - if os.path.isdir(miui_path): - info = imp.find_module("miui_releasetools", [miui_path]) - self.miui_module = imp.load_module("miui_specific", *info) - except ImportError: - print "unable to load miui-specific module; assuming none" - def _DoCall(self, function_name, *args, **kwargs): """Call the named function in the device-specific module, passing the given args and kwargs. The first argument to the call will be the DeviceSpecific object itself. If there is no module, or the module does not define the function, return the value of the 'default' kwarg (which itself defaults to None).""" - # MIUI MOD:START - # if self.module is None or not hasattr(self.module, function_name): - # return kwargs.get("default", None) - # return getattr(self.module, function_name)(*((self,) + args), **kwargs) - run_default = True - if self.module is not None and hasattr(self.module, function_name): - run_default = False - ret = getattr(self.module, function_name)(*((self,) + args), **kwargs) - if self.miui_module is not None and hasattr(self.miui_module, function_name): - getattr(self.miui_module, function_name)(*((self,) + args), **kwargs) - if run_default: + if self.module is None or not hasattr(self.module, function_name): return kwargs.get("default", None) - else: - return ret - #END + return getattr(self.module, function_name)(*((self,) + args), **kwargs) def FullOTA_Assertions(self): """Called after emitting the block of assertions at the top of a @@ -1004,10 +660,6 @@ def FullOTA_Assertions(self): assertions they like.""" return self._DoCall("FullOTA_Assertions") - def FullOTA_InstallBegin(self): - """Called at the start of full OTA installation.""" - return self._DoCall("FullOTA_InstallBegin") - def FullOTA_InstallEnd(self): """Called at the end of full OTA installation; typically this is used to install the image for the device's baseband processor.""" @@ -1019,29 +671,21 @@ def IncrementalOTA_Assertions(self): additional assertions they like.""" return self._DoCall("IncrementalOTA_Assertions") - def IncrementalOTA_VerifyBegin(self): - """Called at the start of the verification phase of incremental - OTA installation; additional checks can be placed here to abort - the script before any changes are made.""" - return self._DoCall("IncrementalOTA_VerifyBegin") - def IncrementalOTA_VerifyEnd(self): """Called at the end of the verification phase of incremental OTA installation; additional checks can be placed here to abort the script before any changes are made.""" return self._DoCall("IncrementalOTA_VerifyEnd") - def IncrementalOTA_InstallBegin(self): - """Called at the start of incremental OTA installation (after - verification is complete).""" - return self._DoCall("IncrementalOTA_InstallBegin") - def IncrementalOTA_InstallEnd(self): """Called at the end of incremental OTA installation; typically this is used to install the image for the device's baseband processor.""" return self._DoCall("IncrementalOTA_InstallEnd") + def WriteRawImage(self, *args): + return self._DoCall("WriteRawImage") + class File(object): def __init__(self, name, data): self.name = name @@ -1062,8 +706,8 @@ def WriteToTemp(self): t.flush() return t - def AddToZip(self, z, compression=None): - ZipWriteStr(z, self.name, self.data, compress_type=compression) + def AddToZip(self, z): + ZipWriteStr(z, self.name, self.data) DIFF_PROGRAM_BY_EXT = { ".gz" : "imgdiff", @@ -1074,11 +718,10 @@ def AddToZip(self, z, compression=None): } class Difference(object): - def __init__(self, tf, sf, diff_program=None): + def __init__(self, tf, sf): self.tf = tf self.sf = sf self.patch = None - self.diff_program = diff_program def ComputePatch(self): """Compute the patch (as a string of data) needed to turn sf into @@ -1087,11 +730,8 @@ def ComputePatch(self): tf = self.tf sf = self.sf - if self.diff_program: - diff_program = self.diff_program - else: - ext = os.path.splitext(tf.name)[1] - diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") + ext = os.path.splitext(tf.name)[1] + diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") ttemp = tf.WriteToTemp() stemp = sf.WriteToTemp() @@ -1101,36 +741,19 @@ def ComputePatch(self): try: ptemp = tempfile.NamedTemporaryFile() if isinstance(diff_program, list): + diff_program[0] = os.path.join(OPTIONS.search_path, "releasetools", diff_program[0]) cmd = copy.copy(diff_program) else: + diff_program = os.path.join(OPTIONS.search_path, "releasetools", diff_program) cmd = [diff_program] cmd.append(stemp.name) cmd.append(ttemp.name) cmd.append(ptemp.name) p = Run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - err = [] - def run(): - _, e = p.communicate() - if e: - err.append(e) - th = threading.Thread(target=run) - th.start() - # MIUI MOD : START - #th.join(timeout=300) # 5 mins - th.join(timeout=1200) # 20 mins - if th.is_alive(): - print "WARNING: diff command timed out" - p.terminate() - th.join(5) - if th.is_alive(): - p.kill() - th.join() - + _, err = p.communicate() if err or p.returncode != 0: - print "WARNING: failure running %s:\n%s\n" % ( - diff_program, "".join(err)) - self.patch = None - return None, None, None + print "WARNING: failure running %s:\n%s\n" % (diff_program, err) + return None diff = ptemp.read() finally: ptemp.close() @@ -1181,7 +804,7 @@ def worker(): print "%8.2f sec %8d / %8d bytes (%6.2f%%) %s" % ( dur, len(patch), tf.size, 100.0 * len(patch) / tf.size, name) lock.release() - except Exception as e: + except Exception, e: print e raise @@ -1194,264 +817,13 @@ def worker(): threads.pop().join() -class BlockDifference(object): - def __init__(self, partition, tgt, src=None, check_first_block=False, - version=None): - self.tgt = tgt - self.src = src - self.partition = partition - self.check_first_block = check_first_block - - # Due to http://b/20939131, check_first_block is disabled temporarily. - assert not self.check_first_block - - if version is None: - version = 1 - if OPTIONS.info_dict: - version = max( - int(i) for i in - OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) - self.version = version - - b = blockimgdiff.BlockImageDiff(tgt, src, threads=OPTIONS.worker_threads, - version=self.version) - tmpdir = tempfile.mkdtemp() - OPTIONS.tempfiles.append(tmpdir) - self.path = os.path.join(tmpdir, partition) - b.Compute(self.path) - - _, self.device = GetTypeAndDevice("/" + partition, OPTIONS.info_dict) - - def WriteScript(self, script, output_zip, progress=None): - if not self.src: - # write the output unconditionally - script.Print("Patching %s image unconditionally..." % (self.partition,)) - else: - script.Print("Patching %s image after verification." % (self.partition,)) - - if progress: - script.ShowProgress(progress, 0) - self._WriteUpdate(script, output_zip) - self._WritePostInstallVerifyScript(script) - - def WriteVerifyScript(self, script): - partition = self.partition - if not self.src: - script.Print("Image %s will be patched unconditionally." % (partition,)) - else: - ranges = self.src.care_map.subtract(self.src.clobbered_blocks) - ranges_str = ranges.to_string_raw() - if self.version >= 3: - script.AppendExtra(('if (range_sha1("%s", "%s") == "%s" || ' - 'block_image_verify("%s", ' - 'package_extract_file("%s.transfer.list"), ' - '"%s.new.dat", "%s.patch.dat")) then') % ( - self.device, ranges_str, self.src.TotalSha1(), - self.device, partition, partition, partition)) - else: - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, self.src.TotalSha1())) - script.Print('Verified %s image...' % (partition,)) - script.AppendExtra('else') - - # When generating incrementals for the system and vendor partitions, - # explicitly check the first block (which contains the superblock) of - # the partition to see if it's what we expect. If this check fails, - # give an explicit log message about the partition having been - # remounted R/W (the most likely explanation) and the need to flash to - # get OTAs working again. - if self.check_first_block: - self._CheckFirstBlock(script) - - # Abort the OTA update. Note that the incremental OTA cannot be applied - # even if it may match the checksum of the target partition. - # a) If version < 3, operations like move and erase will make changes - # unconditionally and damage the partition. - # b) If version >= 3, it won't even reach here. - script.AppendExtra(('abort("%s partition has unexpected contents");\n' - 'endif;') % (partition,)) - - def _WritePostInstallVerifyScript(self, script): - partition = self.partition - script.Print('Verifying the updated %s image...' % (partition,)) - # Unlike pre-install verification, clobbered_blocks should not be ignored. - ranges = self.tgt.care_map - ranges_str = ranges.to_string_raw() - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, - self.tgt.TotalSha1(include_clobbered_blocks=True))) - - # Bug: 20881595 - # Verify that extended blocks are really zeroed out. - if self.tgt.extended: - ranges_str = self.tgt.extended.to_string_raw() - script.AppendExtra('if range_sha1("%s", "%s") == "%s" then' % ( - self.device, ranges_str, - self._HashZeroBlocks(self.tgt.extended.size()))) - script.Print('Verified the updated %s image.' % (partition,)) - script.AppendExtra( - 'else\n' - ' abort("%s partition has unexpected non-zero contents after OTA ' - 'update");\n' - 'endif;' % (partition,)) - else: - script.Print('Verified the updated %s image.' % (partition,)) - - script.AppendExtra( - 'else\n' - ' abort("%s partition has unexpected contents after OTA update");\n' - 'endif;' % (partition,)) - - def _WriteUpdate(self, script, output_zip): - ZipWrite(output_zip, - '{}.transfer.list'.format(self.path), - '{}.transfer.list'.format(self.partition)) - ZipWrite(output_zip, - '{}.new.dat'.format(self.path), - '{}.new.dat'.format(self.partition)) - ZipWrite(output_zip, - '{}.patch.dat'.format(self.path), - '{}.patch.dat'.format(self.partition), - compress_type=zipfile.ZIP_STORED) - - call = ('block_image_update("{device}", ' - 'package_extract_file("{partition}.transfer.list"), ' - '"{partition}.new.dat", "{partition}.patch.dat");\n'.format( - device=self.device, partition=self.partition)) - script.AppendExtra(script.WordWrap(call)) - - def _HashBlocks(self, source, ranges): # pylint: disable=no-self-use - data = source.ReadRangeSet(ranges) - ctx = sha1() - - for p in data: - ctx.update(p) - - return ctx.hexdigest() - - def _HashZeroBlocks(self, num_blocks): # pylint: disable=no-self-use - """Return the hash value for all zero blocks.""" - zero_block = '\x00' * 4096 - ctx = sha1() - for _ in range(num_blocks): - ctx.update(zero_block) - - return ctx.hexdigest() - - # TODO(tbao): Due to http://b/20939131, block 0 may be changed without - # remounting R/W. Will change the checking to a finer-grained way to - # mask off those bits. - def _CheckFirstBlock(self, script): - r = rangelib.RangeSet((0, 1)) - srchash = self._HashBlocks(self.src, r) - - script.AppendExtra(('(range_sha1("%s", "%s") == "%s") || ' - 'abort("%s has been remounted R/W; ' - 'reflash device to reenable OTA updates");') - % (self.device, r.to_string_raw(), srchash, - self.device)) - -DataImage = blockimgdiff.DataImage - - # map recovery.fstab's fs_types to mount/format "partition types" -PARTITION_TYPES = { - "yaffs2": "MTD", - "mtd": "MTD", - "ext4": "EMMC", - "emmc": "EMMC", - "f2fs": "EMMC", - "squashfs": "EMMC" -} +PARTITION_TYPES = { "yaffs2": "MTD", "mtd": "MTD", "ext3": "EMMC", + "ext4": "EMMC", "emmc": "EMMC", "vfat": "EMMC"} def GetTypeAndDevice(mount_point, info): fstab = info["fstab"] if fstab: - return (PARTITION_TYPES[fstab[mount_point].fs_type], - fstab[mount_point].device) + return PARTITION_TYPES[fstab[mount_point].fs_type], fstab[mount_point].device else: - raise KeyError - - -def ParseCertificate(data): - """Parse a PEM-format certificate.""" - cert = [] - save = False - for line in data.split("\n"): - if "--END CERTIFICATE--" in line: - break - if save: - cert.append(line) - if "--BEGIN CERTIFICATE--" in line: - save = True - cert = "".join(cert).decode('base64') - return cert - -def MakeRecoveryPatch(input_dir, output_sink, recovery_img, boot_img, - info_dict=None): - """Generate a binary patch that creates the recovery image starting - with the boot image. (Most of the space in these images is just the - kernel, which is identical for the two, so the resulting patch - should be efficient.) Add it to the output zip, along with a shell - script that is run from init.rc on first boot to actually do the - patching and install the new recovery image. - - recovery_img and boot_img should be File objects for the - corresponding images. info should be the dictionary returned by - common.LoadInfoDict() on the input target_files. - """ - - if info_dict is None: - info_dict = OPTIONS.info_dict - - diff_program = ["imgdiff"] - path = os.path.join(input_dir, "SYSTEM", "etc", "recovery-resource.dat") - if os.path.exists(path): - diff_program.append("-b") - diff_program.append(path) - bonus_args = "-b /system/etc/recovery-resource.dat" - else: - bonus_args = "" - - d = Difference(recovery_img, boot_img, diff_program=diff_program) - _, _, patch = d.ComputePatch() - output_sink("recovery-from-boot.p", patch) - - try: - boot_type, boot_device = GetTypeAndDevice("/boot", info_dict) - recovery_type, recovery_device = GetTypeAndDevice("/recovery", info_dict) - except KeyError: - return - - sh = """#!/system/bin/sh -if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then - applypatch %(bonus_args)s %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p && log -t recovery "Installing new recovery image: succeeded" || log -t recovery "Installing new recovery image: failed" -else - log -t recovery "Recovery image already installed" -fi -""" % {'boot_size': boot_img.size, - 'boot_sha1': boot_img.sha1, - 'recovery_size': recovery_img.size, - 'recovery_sha1': recovery_img.sha1, - 'boot_type': boot_type, - 'boot_device': boot_device, - 'recovery_type': recovery_type, - 'recovery_device': recovery_device, - 'bonus_args': bonus_args} - - # The install script location moved from /system/etc to /system/bin - # in the L release. Parse the init.rc file to find out where the - # target-files expects it to be, and put it there. - sh_location = "etc/install-recovery.sh" - try: - with open(os.path.join(input_dir, "BOOT", "RAMDISK", "init.rc")) as f: - for line in f: - m = re.match(r"^service flash_recovery /system/(\S+)\s*$", line) - if m: - sh_location = m.group(1) - print "putting script in", sh_location - break - except (OSError, IOError) as e: - print "failed to read init.rc: %s" % (e,) - - output_sink(sh_location, sh) + return None diff --git a/releasetools/edify_generator.py b/releasetools/edify_generator.py index 77e0e04..656eca3 100644 --- a/releasetools/edify_generator.py +++ b/releasetools/edify_generator.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import os import re import common @@ -20,15 +21,11 @@ class EdifyGenerator(object): """Class to generate scripts in the 'edify' recovery script language used from donut onwards.""" - def __init__(self, version, info, fstab=None): + def __init__(self, version, info): self.script = [] self.mounts = set() self.version = version self.info = info - if fstab is None: - self.fstab = self.info.get("fstab", None) - else: - self.fstab = fstab def MakeTemporary(self): """Make a temporary script object whose commands can latter be @@ -39,7 +36,7 @@ def MakeTemporary(self): return x @staticmethod - def WordWrap(cmd, linelen=80): + def _WordWrap(cmd, linelen=80): """'cmd' should be a function call with null characters after each parameter (eg, "somefun(foo,\0bar,\0baz)"). This function wraps cmd to a given line length, replacing nulls with spaces and/or newlines @@ -71,57 +68,28 @@ def AppendScript(self, other): with temporary=True) to this one.""" self.script.extend(other.script) - def AssertOemProperty(self, name, value): - """Assert that a property on the OEM paritition matches a value.""" - if not name: - raise ValueError("must specify an OEM property") - if not value: - raise ValueError("must specify the OEM value") - cmd = ('file_getprop("/oem/oem.prop", "{name}") == "{value}" || ' - 'abort("This package expects the value \\"{value}\\" for ' - '\\"{name}\\" on the OEM partition; this has value \\"" + ' - 'file_getprop("/oem/oem.prop", "{name}") + "\\".");').format( - name=name, value=value) - self.script.append(cmd) - def AssertSomeFingerprint(self, *fp): """Assert that the current system build fingerprint is one of *fp.""" if not fp: raise ValueError("must specify some fingerprints") - cmd = (' ||\n '.join([('file_getprop("/system/build.prop", "ro.build.fingerprint") == "%s"') % i - for i in fp]) + - ' ||\n abort("Package expects build fingerprint of %s; this ' - 'device has " + getprop("ro.build.fingerprint") + ".");') % ( - " or ".join(fp)) - self.script.append(cmd) - - def AssertSomeThumbprint(self, *fp): - """Assert that the current system build thumbprint is one of *fp.""" - if not fp: - raise ValueError("must specify some thumbprints") - cmd = (' ||\n '.join([('file_getprop("/system/build.prop", "ro.build.thumbprint") == "%s"') % i - for i in fp]) + - ' ||\n abort("Package expects build thumbprint of %s; this ' - 'device has " + getprop("ro.build.thumbprint") + ".");') % ( - " or ".join(fp)) - self.script.append(cmd) - - def AssertOlderBuild(self, timestamp, timestamp_text): + cmd = ('assert(' + + ' ||\0'.join([('file_getprop("/system/build.prop", ' + '"ro.build.fingerprint") == "%s"') + % i for i in fp]) + + ');') + self.script.append(self._WordWrap(cmd)) + + def AssertOlderBuild(self, timestamp): """Assert that the build on the device is older (or the same as) the given timestamp.""" - self.script.append( - ('(!less_than_int(%s, getprop("ro.build.date.utc"))) || ' - 'abort("Can\'t install this package (%s) over newer ' - 'build (" + getprop("ro.build.date") + ").");') % (timestamp, - timestamp_text)) + self.script.append(('assert(!less_than_int(%s, ' + 'getprop("ro.build.date.utc")));') % (timestamp,)) def AssertDevice(self, device): """Assert that the device identifier is the given string.""" - cmd = ('getprop("ro.product.device") == "%s" || ' - 'abort("This package is for \\"%s\\" devices; ' - 'this is a \\"" + getprop("ro.product.device") + "\\".");') % ( - device, device) - self.script.append(cmd) + cmd = ('assert(getprop("ro.product.device") == "%s" ||\0' + 'getprop("ro.build.product") == "%s");' % (device, device)) + self.script.append(self._WordWrap(cmd)) def AssertSomeBootloader(self, *bootloaders): """Asert that the bootloader version is one of *bootloaders.""" @@ -129,7 +97,7 @@ def AssertSomeBootloader(self, *bootloaders): " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,) for b in bootloaders]) + ");") - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) def ShowProgress(self, frac, dur): """Update the progress bar, advancing it over 'frac' over the next @@ -147,10 +115,9 @@ def PatchCheck(self, filename, *sha1): """Check that the given file (or MTD reference) has one of the given *sha1 hashes, checking the version saved in cache if the file does not match.""" - self.script.append( - 'apply_patch_check("%s"' % (filename,) + - "".join([', "%s"' % (i,) for i in sha1]) + - ') || abort("\\"%s\\" has unexpected contents.");' % (filename,)) + self.script.append('assert(apply_patch_check("%s"' % (filename,) + + "".join([', "%s"' % (i,) for i in sha1]) + + '));') def FileCheck(self, filename, *sha1): """Check that the given file (or MTD reference) has one of the @@ -162,42 +129,25 @@ def FileCheck(self, filename, *sha1): def CacheFreeSpaceCheck(self, amount): """Check that there's at least 'amount' space that can be made available on /cache.""" - self.script.append(('apply_patch_space(%d) || abort("Not enough free space ' - 'on /system to apply patches.");') % (amount,)) - - def Mount(self, mount_point, mount_options_by_format=""): - """Mount the partition with the given mount_point. - mount_options_by_format: - [fs_type=option[,option]...[|fs_type=option[,option]...]...] - where option is optname[=optvalue] - E.g. ext4=barrier=1,nodelalloc,errors=panic|f2fs=errors=recover - """ - fstab = self.fstab + self.script.append("assert(apply_patch_space(%d));" % (amount,)) + + def Mount(self, mount_point): + """Mount the partition with the given mount_point.""" + fstab = self.info.get("fstab", None) if fstab: p = fstab[mount_point] - mount_dict = {} - if mount_options_by_format is not None: - for option in mount_options_by_format.split("|"): - if "=" in option: - key, value = option.split("=", 1) - mount_dict[key] = value - mount_flags = mount_dict.get(p.fs_type, "") - if p.context is not None: - mount_flags = p.context + ("," + mount_flags if mount_flags else "") - self.script.append('mount("%s", "%s", "%s", "%s", "%s");' % ( - p.fs_type, common.PARTITION_TYPES[p.fs_type], p.device, - p.mount_point, mount_flags)) + self.script.append('mount("%s", "%s", "%s", "%s");' % + (p.fs_type, common.PARTITION_TYPES[p.fs_type], + p.device, p.mount_point)) self.mounts.add(p.mount_point) + def Unmount(self, mount_point): + self.script.append('unmount("%s");' % mount_point) + def UnpackPackageDir(self, src, dst): """Unpack a given directory from the OTA package into the given destination directory.""" - # MIUI MOD:START - # self.script.append('package_extract_dir("%s", "%s");' % (src, dst)) - self.script.append( - 'package_extract_dir("%s", "%s") || abort("Failed to extract dir from \\"%s\\" to \\"%s\\".");' % - (src, dst, src, dst)) - # END + self.script.append('package_extract_dir("%s", "%s");' % (src, dst)) def Comment(self, comment): """Write a comment into the update script.""" @@ -210,66 +160,23 @@ def Print(self, message): """Log a message to the screen (if the logs are visible).""" self.script.append('ui_print("%s");' % (message,)) - def TunePartition(self, partition, *options): - fstab = self.fstab - if fstab: - p = fstab[partition] - if p.fs_type not in ("ext2", "ext3", "ext4"): - raise ValueError("Partition %s cannot be tuned\n" % (partition,)) - self.script.append( - 'tune2fs(' + "".join(['"%s", ' % (i,) for i in options]) + - '"%s") || abort("Failed to tune partition %s");' % ( - p.device, partition)) - def FormatPartition(self, partition): """Format the given partition, specified by its mount point (eg, "/system").""" - fstab = self.fstab + reserve_size = 0 + fstab = self.info.get("fstab", None) if fstab: p = fstab[partition] - self.script.append('format("%s", "%s", "%s", "%s", "%s");' % + self.script.append('format("%s", "%s", "%s", "%s");' % (p.fs_type, common.PARTITION_TYPES[p.fs_type], - p.device, p.length, p.mount_point)) - - def WipeBlockDevice(self, partition): - if partition not in ("/system", "/vendor"): - raise ValueError(("WipeBlockDevice doesn't work on %s\n") % (partition,)) - fstab = self.fstab - size = self.info.get(partition.lstrip("/") + "_size", None) - device = fstab[partition].device - - self.script.append('wipe_block_device("%s", %s);' % (device, size)) + p.device, p.length)) def DeleteFiles(self, file_list): """Delete all files in file_list.""" - if not file_list: - return + if not file_list: return cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");" - self.script.append(self.WordWrap(cmd)) - - def DeleteFilesIfNotMatching(self, file_list): - """Delete the file in file_list if not matching the checksum.""" - if not file_list: - return - for name, sha1 in file_list: - cmd = ('sha1_check(read_file("{name}"), "{sha1}") || ' - 'delete("{name}");'.format(name=name, sha1=sha1)) - self.script.append(self.WordWrap(cmd)) - - def RenameFile(self, srcfile, tgtfile): - """Moves a file from one location to another.""" - if self.info.get("update_rename_support", False): - self.script.append('rename("%s", "%s");' % (srcfile, tgtfile)) - else: - raise ValueError("Rename not supported by update binary") - - def SkipNextActionIfTargetExists(self, tgtfile, tgtsha1): - """Prepend an action with an apply_patch_check in order to - skip the action if the file exists. Used when a patch - is later renamed.""" - cmd = ('sha1_check(read_file("%s"), %s) ||' % (tgtfile, tgtsha1)) - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): """Apply binary patches (in *patchpairs) to the given srcfile to @@ -279,24 +186,17 @@ def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): raise ValueError("bad patches given to ApplyPatch") cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d' % (srcfile, tgtfile, tgtsha1, tgtsize)] - # MIUI MOD:START - # for i in range(0, len(patchpairs), 2): - # cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) - # cmd.append(');') - patchfiles = "" for i in range(0, len(patchpairs), 2): cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) - patchfiles = patchfiles.join('%s ' % patchpairs[i+1]) - cmd.append(') || abort("Failed to apply patch \\"%s\\".");' % (patchfiles,)) - # END + cmd.append(');') cmd = "".join(cmd) - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) - def WriteRawImage(self, mount_point, fn, mapfn=None): + def WriteRawImage(self, mount_point, fn): """Write the given package file into the partition for the given mount point.""" - fstab = self.fstab + fstab = self.info["fstab"] if fstab: p = fstab[mount_point] partition_type = common.PARTITION_TYPES[p.fs_type] @@ -306,46 +206,19 @@ def WriteRawImage(self, mount_point, fn, mapfn=None): 'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");' % args) elif partition_type == "EMMC": - if mapfn: - args["map"] = mapfn - self.script.append( - 'package_extract_file("%(fn)s", "%(device)s", "%(map)s");' % args) - else: - self.script.append( - 'package_extract_file("%(fn)s", "%(device)s");' % args) + self.script.append( + 'package_extract_file("%(fn)s", "%(device)s");' % args) else: - raise ValueError( - "don't know how to write \"%s\" partitions" % p.fs_type) + raise ValueError("don't know how to write \"%s\" partitions" % (p.fs_type,)) - def SetPermissions(self, fn, uid, gid, mode, selabel, capabilities): + def SetPermissions(self, fn, uid, gid, mode): """Set file ownership and permissions.""" - if not self.info.get("use_set_metadata", False): - self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) - else: - cmd = 'set_metadata("%s", "uid", %d, "gid", %d, "mode", 0%o' % (fn, uid, gid, mode) - if capabilities is not None: - cmd += ', "capabilities", "%s"' % capabilities - if selabel is not None: - cmd += ', "selabel", "%s"' % selabel - cmd += ');' - self.script.append(cmd) - - def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode, selabel, - capabilities): + self.script.append('set_perm(%d, %d, 0%o, "%s");' % (uid, gid, mode, fn)) + + def SetPermissionsRecursive(self, fn, uid, gid, dmode, fmode): """Recursively set path ownership and permissions.""" - if not self.info.get("use_set_metadata", False): - self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' - % (uid, gid, dmode, fmode, fn)) - else: - if capabilities is None: - capabilities = "0x0" - cmd = 'set_metadata_recursive("%s", "uid", %d, "gid", %d, ' \ - '"dmode", 0%o, "fmode", 0%o, "capabilities", %s' \ - % (fn, uid, gid, dmode, fmode, capabilities) - if selabel is not None: - cmd += ', "selabel", "%s"' % selabel - cmd += ');' - self.script.append(cmd) + self.script.append('set_perm_recursive(%d, %d, 0%o, 0%o, "%s");' + % (uid, gid, dmode, fmode, fn)) def MakeSymlinks(self, symlink_list): """Create symlinks, given a list of (dest, link) pairs.""" @@ -356,16 +229,26 @@ def MakeSymlinks(self, symlink_list): for dest, links in sorted(by_dest.iteritems()): cmd = ('symlink("%s", ' % (dest,) + ",\0".join(['"' + i + '"' for i in sorted(links)]) + ");") - self.script.append(self.WordWrap(cmd)) + self.script.append(self._WordWrap(cmd)) + + def RetouchBinaries(self, file_list): + """Execute the retouch instructions in files listed.""" + cmd = ('retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) + + def UndoRetouchBinaries(self, file_list): + """Undo the retouching (retouch to zero offset).""" + cmd = ('undo_retouch_binaries(' + + ', '.join(['"' + i[0] + '", "' + i[1] + '"' for i in file_list]) + + ');') + self.script.append(self._WordWrap(cmd)) def AppendExtra(self, extra): """Append text verbatim to the output script.""" self.script.append(extra) - def Unmount(self, mount_point): - self.script.append('unmount("%s");' % mount_point) - self.mounts.remove(mount_point) - def UnmountAll(self): for p in sorted(self.mounts): self.script.append('unmount("%s");' % (p,)) @@ -385,6 +268,6 @@ def AddToZip(self, input_zip, output_zip, input_path=None): if input_path is None: data = input_zip.read("OTA/bin/updater") else: - data = open(input_path, "rb").read() + data = open(os.path.join(input_path, "updater")).read() common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary", - data, perms=0o755) + data, perms=0755) diff --git a/linux-x86/imgdiff b/releasetools/imgdiff similarity index 100% rename from linux-x86/imgdiff rename to releasetools/imgdiff diff --git a/releasetools/miui_releasetools.py b/releasetools/miui_releasetools.py deleted file mode 100644 index 73d563b..0000000 --- a/releasetools/miui_releasetools.py +++ /dev/null @@ -1,109 +0,0 @@ - -import common -import copy -import edify_generator - -def FullOTA_Assertions(info): - info.script.Mount("/data") - -def IncrementalOTA_Assertions(info): - info.script.Mount("/data") - -def PushBusybox(input_zip, output_zip, script): - try: - data = input_zip.read("OTA/bin/busybox") - common.ZipWriteStr(output_zip, "META-INF/com/miui/busybox", data) - script.AppendExtra("package_extract_file(\"META-INF/com/miui/busybox\", \"/tmp/busybox\");") - script.SetPermissions("/tmp/busybox", 0, 0, 0555, None, None) - except KeyError: - print 'Ignore replace cert' - -def RemoveUseslessFiles(script): - script.DeleteFiles(["/tmp/busybox"]) - -def ProcessSystemFormat(info): - edify = info.script - script_temp = edify_generator.EdifyGenerator(3, info.script.info) - PushBusybox(info.input_zip, info.output_zip, script_temp) - script_temp.AppendExtra("run_program(\"/tmp/busybox\", \"rm\", \"-rf\", \"/system\");") - script_temp_str = "".join(script_temp.script).replace(";", ";\n").strip() - format_system_line = 0 - mount_system_line = 0 - for i in xrange(len(edify.script)): - if format_system_line > 0 and mount_system_line > 0: - break - if ");" in edify.script[i] and "format" in edify.script[i] and "/system" in edify.script[i]: - format_system_line = i - continue - elif ");" in edify.script[i] and "mount" in edify.script[i] and "/system" in edify.script[i]: - mount_system_line = i - continue - if mount_system_line > format_system_line > 0: - edify.script[format_system_line] = edify.script[format_system_line].replace(edify.script[format_system_line], edify.script[mount_system_line]) - edify.script[mount_system_line] = edify.script[mount_system_line].replace(edify.script[mount_system_line] , script_temp_str) - elif format_system_line > mount_system_line > 0: - edify.script[format_system_line] = edify.script[format_system_line].replace(edify.script[format_system_line], "") - edify.script[mount_system_line] = edify.script[mount_system_line].replace(";", ";\n" + script_temp_str) - else: - PushBusybox(info.input_zip, info.output_zip, info.script) - -def FullOTA_InstallEnd(info): - UnpackData(info.script) - CopyDataFiles(info.input_zip, info.output_zip, info.script) - ProcessSystemFormat(info) - Replace_Cert(info.input_zip, info.output_zip, info.script) - RemoveUseslessFiles(info.script) - SetPermissions(info.script) - RemoveAbandonedPreinstall(info.script) - - -def IncrementalOTA_InstallEnd(info): - UnpackData(info.script) - Replace_Cert(info.target_zip, info.output_zip, info.script) - SetPermissions(info.script) - RemoveAbandonedPreinstall(info.script) - -def CopyDataFiles(input_zip, output_zip, script): - """Copies files underneath data/miui in the input zip to the output zip.""" - - print "[MIUI CUST] OTA: copy data files" - for info in input_zip.infolist(): - if info.filename.startswith("DATA/miui/"): - basefilename = info.filename[5:] - info2 = copy.copy(info) - info2.filename = "data/" + basefilename - data = input_zip.read(info.filename) - output_zip.writestr(info2, data) - - -def UnpackData(script): - script.UnpackPackageDir("data", "/data") - - -def SetPermissions(script): - print "[MIUI CUST] OTA: SetPermissions" - SetPermissionsRecursive(script, "/data/miui", 1000, 1000, 0755, 0644) - - -def SetPermissionsRecursive(script, d, gid, uid, dmod, fmod): - try: - script.SetPermissionsRecursive(d, gid, uid, dmod, fmod) - except TypeError: - script.SetPermissionsRecursive(d, gid, uid, dmod, fmod, None, None) - - -def RemoveAbandonedPreinstall(script): - script.AppendExtra("delete_recursive(\"/data/miui/preinstall_apps\");") - script.AppendExtra("delete_recursive(\"/data/miui/cust/preinstall_apps\");") - -def Replace_Cert(input_zip, output_zip, script): - try: - data = input_zip.read("OTA/bin/replace_key") - common.ZipWriteStr(output_zip, "META-INF/com/miui/replace_key", data) - script.AppendExtra("package_extract_file(\"META-INF/com/miui/replace_key\", \"/tmp/replace_key\");") - script.SetPermissions("/tmp/replace_key", 0, 0, 0555, None, None) - script.AppendExtra("run_program(\"/sbin/sh\", \"/tmp/replace_key\");") - script.DeleteFiles(["/tmp/replace_key"]) - except KeyError: - print 'Ignore replace cert' - diff --git a/releasetools/ota_from_target_files b/releasetools/ota_from_target_files index 00e2a46..3f12468 100755 --- a/releasetools/ota_from_target_files +++ b/releasetools/ota_from_target_files @@ -21,7 +21,7 @@ a full OTA is produced. Usage: ota_from_target_files [flags] input_target_files output_ota_package - --board_config + -b (--board_config) Deprecated. -k (--package_key) Key to use to sign the package (default is @@ -37,19 +37,6 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package Generate an incremental OTA using the given target-files zip as the starting build. - --full_radio - When generating an incremental OTA, always include a full copy of - radio image. This option is only meaningful when -i is specified, - because a full radio is always included in a full OTA if applicable. - - -v (--verify) - Remount and verify the checksums of the files written to the - system and vendor (if used) partitions. Incremental builds only. - - -o (--oem_settings) - Use the file to specify the expected OEM-specific properties - on the OEM partition of the intended device. - -w (--wipe_user_data) Generate an OTA package that will wipe the user data partition when installed. @@ -64,47 +51,34 @@ Usage: ota_from_target_files [flags] input_target_files output_ota_package -a (--aslr_mode) Specify whether to turn on ASLR for the package (on by default). - - -2 (--two_step) - Generate a 'two-step' OTA package, where recovery is updated - first, so that any changes made to the system partition are done - using the new recovery (new kernel, etc.). - - --block - Generate a block-based OTA if possible. Will fall back to a - file-based OTA if the target_files is older and doesn't support - block-based OTAs. - - -b (--binary) - Use the given binary as the update-binary in the output package, - instead of the binary in the build's target_files. Use for - development only. - - -t (--worker_threads) - Specifies the number of worker-threads that will be used when - generating patches for incremental updates (defaults to 3). - """ import sys -if sys.hexversion < 0x02070000: - print >> sys.stderr, "Python 2.7 or newer is required." +if sys.hexversion < 0x02040000: + print >> sys.stderr, "Python 2.4 or newer is required." sys.exit(1) -import multiprocessing +import copy +import errno import os +import re +import subprocess import tempfile +import time import zipfile +try: + from hashlib import sha1 as sha1 +except ImportError: + from sha import sha as sha1 + import common import edify_generator -import sparse_img OPTIONS = common.OPTIONS OPTIONS.package_key = None OPTIONS.incremental_source = None -OPTIONS.verify = False OPTIONS.require_verbatim = set() OPTIONS.prohibit_verbatim = set(("system/build.prop",)) OPTIONS.patch_threshold = 0.95 @@ -112,23 +86,13 @@ OPTIONS.wipe_user_data = False OPTIONS.omit_prereq = False OPTIONS.extra_script = None OPTIONS.aslr_mode = True -OPTIONS.worker_threads = multiprocessing.cpu_count() // 2 -if OPTIONS.worker_threads == 0: - OPTIONS.worker_threads = 1 -OPTIONS.two_step = False -OPTIONS.no_signing = False -OPTIONS.block_based = False -OPTIONS.updater_binary = None -OPTIONS.oem_source = None -OPTIONS.fallback_to_full = True -OPTIONS.full_radio = False +OPTIONS.worker_threads = 3 def MostPopularKey(d, default): """Given a dict, return the key corresponding to the largest value. Returns 'default' if the dict is empty.""" x = [(v, k) for (k, v) in d.iteritems()] - if not x: - return default + if not x: return default x.sort() return x[-1][1] @@ -136,187 +100,133 @@ def MostPopularKey(d, default): def IsSymlink(info): """Return true if the zipfile.ZipInfo object passed in represents a symlink.""" - return (info.external_attr >> 28) == 0o12 + return (info.external_attr >> 16) == 0120777 def IsRegular(info): """Return true if the zipfile.ZipInfo object passed in represents a symlink.""" - return (info.external_attr >> 28) == 0o10 - -def ClosestFileMatch(src, tgtfiles, existing): - """Returns the closest file match between a source file and list - of potential matches. The exact filename match is preferred, - then the sha1 is searched for, and finally a file with the same - basename is evaluated. Rename support in the updater-binary is - required for the latter checks to be used.""" - - result = tgtfiles.get("path:" + src.name) - if result is not None: - return result - - # MIUI ADD: - # disable rename support - return None - - if not OPTIONS.target_info_dict.get("update_rename_support", False): - return None - - if src.size < 1000: - return None - - result = tgtfiles.get("sha1:" + src.sha1) - if result is not None and existing.get(result.name) is None: - return result - result = tgtfiles.get("file:" + src.name.split("/")[-1]) - if result is not None and existing.get(result.name) is None: - return result - return None - -class ItemSet(object): - def __init__(self, partition, fs_config): - self.partition = partition - self.fs_config = fs_config - self.ITEMS = {} - - def Get(self, name, is_dir=False): - if name not in self.ITEMS: - self.ITEMS[name] = Item(self, name, is_dir=is_dir) - return self.ITEMS[name] - - def GetMetadata(self, input_zip): - # The target_files contains a record of what the uid, - # gid, and mode are supposed to be. - output = input_zip.read(self.fs_config) - - for line in output.split("\n"): - if not line: - continue - columns = line.split() - name, uid, gid, mode = columns[:4] - selabel = None - capabilities = None - - # After the first 4 columns, there are a series of key=value - # pairs. Extract out the fields we care about. - for element in columns[4:]: - key, value = element.split("=") - if key == "selabel": - selabel = value - if key == "capabilities": - capabilities = value - - i = self.ITEMS.get(name, None) - if i is not None: - i.uid = int(uid) - i.gid = int(gid) - i.mode = int(mode, 8) - i.selabel = selabel - i.capabilities = capabilities - if i.is_dir: - i.children.sort(key=lambda i: i.name) - - # set metadata for the files generated by this script. - # MIUI MOD: - if self.partition == "system": - i = self.ITEMS.get("system/recovery-from-boot.p", None) - if i: - i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o644, None, None - i = self.ITEMS.get("system/etc/install-recovery.sh", None) - if i: - i.uid, i.gid, i.mode, i.selabel, i.capabilities = 0, 0, 0o544, None, None + return (info.external_attr >> 28) == 010 - -class Item(object): +class Item: """Items represent the metadata (user, group, mode) of files and directories in the system image.""" - def __init__(self, itemset, name, is_dir=False): - self.itemset = itemset + ITEMS = {} + def __init__(self, name, dir=False): self.name = name self.uid = 0 self.gid = 0 - self.mode = 0o644 - self.selabel = None - self.capabilities = None - self.is_dir = is_dir - self.descendants = None - self.best_subtree = None + self.mode = 0644 + self.dir = dir + if dir: + self.mode = 0755 if name: - self.parent = itemset.Get(os.path.dirname(name), is_dir=True) + self.parent = Item.Get(os.path.dirname(name), dir=True) self.parent.children.append(self) else: self.parent = None - if self.is_dir: + if dir: self.children = [] def Dump(self, indent=0): if self.uid is not None: - print "%s%s %d %d %o" % ( - " " * indent, self.name, self.uid, self.gid, self.mode) + print "%s%s %d %d %o" % (" "*indent, self.name, self.uid, self.gid, self.mode) else: - print "%s%s %s %s %s" % ( - " " * indent, self.name, self.uid, self.gid, self.mode) - if self.is_dir: + print "%s%s %s %s %s" % (" "*indent, self.name, self.uid, self.gid, self.mode) + if self.dir: print "%s%s" % (" "*indent, self.descendants) print "%s%s" % (" "*indent, self.best_subtree) for i in self.children: i.Dump(indent=indent+1) + @classmethod + def Get(cls, name, dir=False): + if name not in cls.ITEMS: + cls.ITEMS[name] = Item(name, dir=dir) + return cls.ITEMS[name] + + @classmethod + def GetMetadata(cls, input_zip): + + try: + # See if the target_files contains a record of what the uid, + # gid, and mode is supposed to be. + output = input_zip.read("META/filesystem_config.txt") + except KeyError: + # Run the external 'fs_config' program to determine the desired + # uid, gid, and mode for every Item object. Note this uses the + # one in the client now, which might not be the same as the one + # used when this target_files was built. + p = common.Run(["fs_config"], stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + suffix = { False: "", True: "/" } + input = "".join(["%s%s\n" % (i.name, suffix[i.dir]) + for i in cls.ITEMS.itervalues() if i.name]) + output, error = p.communicate(input) + assert not error + + for line in output.split("\n"): + if not line: continue + rows = line.split() + length = len(rows) + name = ' '.join(rows[0:length-3]) + uid, gid, mode = rows[length-3:] + i = cls.ITEMS.get(name, None) + if i is not None: + i.uid = int(uid) + i.gid = int(gid) + i.mode = int(mode, 8) + if i.dir: + i.children.sort(key=lambda i: i.name) + + # set metadata for the files generated by this script. + i = cls.ITEMS.get("system/recovery-from-boot.p", None) + if i: i.uid, i.gid, i.mode = 0, 0, 0644 + i = cls.ITEMS.get("system/etc/install-recovery.sh", None) + if i: i.uid, i.gid, i.mode = 0, 0, 0544 + def CountChildMetadata(self): - """Count up the (uid, gid, mode, selabel, capabilities) tuples for - all children and determine the best strategy for using set_perm_recursive - and set_perm to correctly chown/chmod all the files to their desired + """Count up the (uid, gid, mode) tuples for all children and + determine the best strategy for using set_perm_recursive and + set_perm to correctly chown/chmod all the files to their desired values. Recursively calls itself for all descendants. - Returns a dict of {(uid, gid, dmode, fmode, selabel, capabilities): count} - counting up all descendants of this node. (dmode or fmode may be None.) - Also sets the best_subtree of each directory Item to the (uid, gid, dmode, - fmode, selabel, capabilities) tuple that will match the most descendants of - that Item. + Returns a dict of {(uid, gid, dmode, fmode): count} counting up + all descendants of this node. (dmode or fmode may be None.) Also + sets the best_subtree of each directory Item to the (uid, gid, + dmode, fmode) tuple that will match the most descendants of that + Item. """ - assert self.is_dir - key = (self.uid, self.gid, self.mode, None, self.selabel, - self.capabilities) - self.descendants = {key: 1} - d = self.descendants + assert self.dir + d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} for i in self.children: - if i.is_dir: + if i.dir: for k, v in i.CountChildMetadata().iteritems(): d[k] = d.get(k, 0) + v else: - k = (i.uid, i.gid, None, i.mode, i.selabel, i.capabilities) + k = (i.uid, i.gid, None, i.mode) d[k] = d.get(k, 0) + 1 - # Find the (uid, gid, dmode, fmode, selabel, capabilities) - # tuple that matches the most descendants. + # Find the (uid, gid, dmode, fmode) tuple that matches the most + # descendants. # First, find the (uid, gid) pair that matches the most # descendants. ug = {} - for (uid, gid, _, _, _, _), count in d.iteritems(): + for (uid, gid, _, _), count in d.iteritems(): ug[(uid, gid)] = ug.get((uid, gid), 0) + count ug = MostPopularKey(ug, (0, 0)) - # Now find the dmode, fmode, selabel, and capabilities that match - # the most descendants with that (uid, gid), and choose those. - best_dmode = (0, 0o755) - best_fmode = (0, 0o644) - best_selabel = (0, None) - best_capabilities = (0, None) + # Now find the dmode and fmode that match the most descendants + # with that (uid, gid), and choose those. + best_dmode = (0, 0755) + best_fmode = (0, 0644) for k, count in d.iteritems(): - if k[:2] != ug: - continue - if k[2] is not None and count >= best_dmode[0]: - best_dmode = (count, k[2]) - if k[3] is not None and count >= best_fmode[0]: - best_fmode = (count, k[3]) - if k[4] is not None and count >= best_selabel[0]: - best_selabel = (count, k[4]) - if k[5] is not None and count >= best_capabilities[0]: - best_capabilities = (count, k[5]) - self.best_subtree = ug + ( - best_dmode[1], best_fmode[1], best_selabel[1], best_capabilities[1]) + if k[:2] != ug: continue + if k[2] is not None and count >= best_dmode[0]: best_dmode = (count, k[2]) + if k[3] is not None and count >= best_fmode[0]: best_fmode = (count, k[3]) + self.best_subtree = ug + (best_dmode[1], best_fmode[1]) return d @@ -328,57 +238,52 @@ class Item(object): self.CountChildMetadata() def recurse(item, current): - # current is the (uid, gid, dmode, fmode, selabel, capabilities) tuple - # that the current item (and all its children) have already been set to. - # We only need to issue set_perm/set_perm_recursive commands if we're + # current is the (uid, gid, dmode, fmode) tuple that the current + # item (and all its children) have already been set to. We only + # need to issue set_perm/set_perm_recursive commands if we're # supposed to be something different. - if item.is_dir: + if item.dir: if current != item.best_subtree: script.SetPermissionsRecursive("/"+item.name, *item.best_subtree) current = item.best_subtree if item.uid != current[0] or item.gid != current[1] or \ - item.mode != current[2] or item.selabel != current[4] or \ - item.capabilities != current[5]: - script.SetPermissions("/"+item.name, item.uid, item.gid, - item.mode, item.selabel, item.capabilities) + item.mode != current[2]: + script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) for i in item.children: recurse(i, current) else: if item.uid != current[0] or item.gid != current[1] or \ - item.mode != current[3] or item.selabel != current[4] or \ - item.capabilities != current[5]: - script.SetPermissions("/"+item.name, item.uid, item.gid, - item.mode, item.selabel, item.capabilities) + item.mode != current[3]: + script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) - recurse(self, (-1, -1, -1, -1, None, None)) + recurse(self, (-1, -1, -1, -1)) -def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): - """Copies files for the partition in the input zip to the output +def CopySystemFiles(input_zip, output_zip=None, + substitute=None): + """Copies files underneath system/ in the input zip to the output zip. Populates the Item class with their metadata, and returns a - list of symlinks. output_zip may be None, in which case the copy is - skipped (but the other side effects still happen). substitute is an - optional dict of {output filename: contents} to be output instead of - certain input files. + list of symlinks as well as a list of files that will be retouched. + output_zip may be None, in which case the copy is skipped (but the + other side effects still happen). substitute is an optional dict + of {output filename: contents} to be output instead of certain input + files. """ symlinks = [] - - partition = itemset.partition + retouch_files = [] for info in input_zip.infolist(): - prefix = partition.upper() + "/" - if info.filename.startswith(prefix): - basefilename = info.filename[len(prefix):] + if info.filename.startswith("SYSTEM/"): + basefilename = info.filename[7:] if IsSymlink(info): symlinks.append((input_zip.read(info.filename), - "/" + partition + "/" + basefilename)) + "/system/" + basefilename)) else: - import copy info2 = copy.copy(info) - fn = info2.filename = partition + "/" + basefilename + fn = info2.filename = "system/" + basefilename if substitute and fn in substitute and substitute[fn] is None: continue if output_zip is not None: @@ -386,15 +291,29 @@ def CopyPartitionFiles(itemset, input_zip, output_zip=None, substitute=None): data = substitute[fn] else: data = input_zip.read(info.filename) - common.ZipWriteStr(output_zip, info2, data) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + common.sha1(data).hexdigest())) + output_zip.writestr(info2, data) if fn.endswith("/"): - itemset.Get(fn[:-1], is_dir=True) + Item.Get(fn[:-1], dir=True) else: - itemset.Get(fn) + Item.Get(fn, dir=False) symlinks.sort() - return symlinks + return (symlinks, retouch_files) +def CopyDataFiles(input_zip, output_zip=None): + """Copies files underneath data/ in the input zip to the output zip.""" + + for info in input_zip.infolist(): + if info.filename.startswith("DATA/preinstall_apps"): + basefilename = info.filename[5:] + info2 = copy.copy(info) + info2.filename = "data/" + basefilename + if output_zip is not None: + data = input_zip.read(info.filename) + output_zip.writestr(info2, data) def SignOutput(temp_zip_name, output_zip_name): key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) @@ -404,124 +323,65 @@ def SignOutput(temp_zip_name, output_zip_name): whole_file=True) -def AppendAssertions(script, info_dict, oem_dict=None): - oem_props = info_dict.get("oem_fingerprint_properties") - if oem_props is None or len(oem_props) == 0: - device = GetBuildProp("ro.product.device", info_dict) - script.AssertDevice(device) - else: - if oem_dict is None: - raise common.ExternalError( - "No OEM file provided to answer expected assertions") - for prop in oem_props.split(): - if oem_dict.get(prop) is None: - raise common.ExternalError( - "The OEM file is missing the property %s" % prop) - script.AssertOemProperty(prop, oem_dict.get(prop)) - - -def HasRecoveryPatch(target_files_zip): - try: - target_files_zip.getinfo("SYSTEM/recovery-from-boot.p") - return True - except KeyError: - return False - -def HasVendorPartition(target_files_zip): - try: - target_files_zip.getinfo("VENDOR/") - return True - except KeyError: - return False - -# MIUI ADD -def HasCustPartition(target_files_zip): - try: - target_files_zip.getinfo("CUST/") - return True - except KeyError: - return False - -def GetOemProperty(name, oem_props, oem_dict, info_dict): - if oem_props is not None and name in oem_props: - return oem_dict[name] - return GetBuildProp(name, info_dict) - - -def CalculateFingerprint(oem_props, oem_dict, info_dict): - if oem_props is None: - return GetBuildProp("ro.build.fingerprint", info_dict) - return "%s/%s/%s:%s" % ( - GetOemProperty("ro.product.brand", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.name", oem_props, oem_dict, info_dict), - GetOemProperty("ro.product.device", oem_props, oem_dict, info_dict), - GetBuildProp("ro.build.thumbprint", info_dict)) - - -def GetImage(which, tmpdir, info_dict): - # Return an image object (suitable for passing to BlockImageDiff) - # for the 'which' partition (most be "system" or "vendor"). If a - # prebuilt image and file map are found in tmpdir they are used, - # otherwise they are reconstructed from the individual files. +def AppendAssertions(script, input_zip): + device = GetBuildProp("ro.product.device", input_zip) + script.AssertDevice(device) - assert which in ("system", "vendor") - path = os.path.join(tmpdir, "IMAGES", which + ".img") - mappath = os.path.join(tmpdir, "IMAGES", which + ".map") - if os.path.exists(path) and os.path.exists(mappath): - print "using %s.img from target-files" % (which,) - # This is a 'new' target-files, which already has the image in it. +def MakeRecoveryPatch(output_zip, recovery_img, boot_img): + """Generate a binary patch that creates the recovery image starting + with the boot image. (Most of the space in these images is just the + kernel, which is identical for the two, so the resulting patch + should be efficient.) Add it to the output zip, along with a shell + script that is run from init.rc on first boot to actually do the + patching and install the new recovery image. - else: - print "building %s.img from target-files" % (which,) - - # This is an 'old' target-files, which does not contain images - # already built. Build them. + recovery_img and boot_img should be File objects for the + corresponding images. info should be the dictionary returned by + common.LoadInfoDict() on the input target_files. - mappath = tempfile.mkstemp()[1] - OPTIONS.tempfiles.append(mappath) + Returns an Item for the shell script, which must be made + executable. + """ - import add_img_to_target_files - if which == "system": - path = add_img_to_target_files.BuildSystem( - tmpdir, info_dict, block_list=mappath) - elif which == "vendor": - path = add_img_to_target_files.BuildVendor( - tmpdir, info_dict, block_list=mappath) + d = common.Difference(recovery_img, boot_img) + _, _, patch = d.ComputePatch() + common.ZipWriteStr(output_zip, "recovery/recovery-from-boot.p", patch) + Item.Get("system/recovery-from-boot.p", dir=False) - # Bug: http://b/20939131 - # In ext4 filesystems, block 0 might be changed even being mounted - # R/O. We add it to clobbered_blocks so that it will be written to the - # target unconditionally. Note that they are still part of care_map. - clobbered_blocks = "0" + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) + recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict) - return sparse_img.SparseImage(path, mappath, clobbered_blocks) + sh = """#!/system/bin/sh +if ! applypatch -c %(recovery_type)s:%(recovery_device)s:%(recovery_size)d:%(recovery_sha1)s; then + log -t recovery "Installing new recovery image" + applypatch %(boot_type)s:%(boot_device)s:%(boot_size)d:%(boot_sha1)s %(recovery_type)s:%(recovery_device)s %(recovery_sha1)s %(recovery_size)d %(boot_sha1)s:/system/recovery-from-boot.p +else + log -t recovery "Recovery image already installed" +fi +""" % { 'boot_size': boot_img.size, + 'boot_sha1': boot_img.sha1, + 'recovery_size': recovery_img.size, + 'recovery_sha1': recovery_img.sha1, + 'boot_type': boot_type, + 'boot_device': boot_device, + 'recovery_type': recovery_type, + 'recovery_device': recovery_device, + } + common.ZipWriteStr(output_zip, "recovery/etc/install-recovery.sh", sh) + return Item.Get("system/etc/install-recovery.sh", dir=False) def WriteFullOTAPackage(input_zip, output_zip): # TODO: how to determine this? We don't know what version it will - # be installed on top of. For now, we expect the API just won't - # change very often. Similarly for fstab, it might have changed - # in the target build. + # be installed on top of. For now, we expect the API just won't + # change very often. script = edify_generator.EdifyGenerator(3, OPTIONS.info_dict) - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - metadata = { - "post-build": CalculateFingerprint(oem_props, oem_dict, - OPTIONS.info_dict), - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", OPTIONS.info_dict), - } + metadata = {"post-build": GetBuildProp("ro.build.fingerprint", input_zip), + "pre-device": GetBuildProp("ro.product.device", input_zip), + "post-timestamp": GetBuildProp("ro.build.date.utc", input_zip), + } device_specific = common.DeviceSpecificParams( input_zip=input_zip, @@ -532,239 +392,128 @@ def WriteFullOTAPackage(input_zip, output_zip): metadata=metadata, info_dict=OPTIONS.info_dict) - has_recovery_patch = HasRecoveryPatch(input_zip) - block_based = OPTIONS.block_based and has_recovery_patch - if not OPTIONS.omit_prereq: - ts = GetBuildProp("ro.build.date.utc", OPTIONS.info_dict) - ts_text = GetBuildProp("ro.build.date", OPTIONS.info_dict) - script.AssertOlderBuild(ts, ts_text) + ts = GetBuildProp("ro.build.date.utc", input_zip) + script.AssertOlderBuild(ts) - AppendAssertions(script, OPTIONS.info_dict, oem_dict) + AppendAssertions(script, input_zip) device_specific.FullOTA_Assertions() - # Two-step package strategy (in chronological order, which is *not* - # the order in which the generated script has things): - # - # if stage is not "2/3" or "3/3": - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # set stage to "" - # do normal full package installation: - # wipe and install system, boot image, etc. - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - #recovery_img = common.GetBootableImage("recovery.img", "recovery.img", - # OPTIONS.input_tmp, "RECOVERY") - #if OPTIONS.two_step: - # if not OPTIONS.info_dict.get("multistage_support", None): - # assert False, "two-step packages not supported by this build" - # fs = OPTIONS.info_dict["fstab"]["/misc"] - # assert fs.fs_type.upper() == "EMMC", \ - # "two-step packages only supported on devices with EMMC /misc partitions" - # bcb_dev = {"bcb_dev": fs.device} - # common.ZipWriteStr(output_zip, "recovery.img", recovery_img.data) - # script.AppendExtra(""" -#if get_stage("%(bcb_dev)s") == "2/3" then -#""" % bcb_dev) -# script.WriteRawImage("/recovery", "recovery.img") -# script.AppendExtra(""" -#set_stage("%(bcb_dev)s", "3/3"); -#reboot_now("%(bcb_dev)s", "recovery"); -#else if get_stage("%(bcb_dev)s") == "3/3" then -#""" % bcb_dev) - - # Dump fingerprints - script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.info_dict)) - - device_specific.FullOTA_InstallBegin() - - system_progress = 0.75 + script.ShowProgress(0.5, 0) if OPTIONS.wipe_user_data: - system_progress -= 0.1 - if HasVendorPartition(input_zip): - system_progress -= 0.1 - # MIUI ADD: - if HasCustPartition(input_zip): - system_progress -= 0.1 - - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - - recovery_mount_options = OPTIONS.info_dict.get("recovery_mount_options") - - system_items = ItemSet("system", "META/filesystem_config.txt") - script.ShowProgress(system_progress, 0) - - if block_based: - # Full OTA is done as an "incremental" against an empty source - # image. This has the effect of writing new data from the package - # to the entire partition, but lets us reuse the updater code that - # writes incrementals to do it. - system_tgt = GetImage("system", OPTIONS.input_tmp, OPTIONS.info_dict) - system_tgt.ResetFileMap() - system_diff = common.BlockDifference("system", system_tgt, src=None) - system_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/system") - script.Mount("/system", recovery_mount_options) - if not has_recovery_patch: - script.UnpackPackageDir("recovery", "/system") - script.UnpackPackageDir("system", "/system") - - symlinks = CopyPartitionFiles(system_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - - boot_img = common.GetBootableImage("boot.img", "boot.img", - OPTIONS.input_tmp, "BOOT") - - if not block_based: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn) - - #common.MakeRecoveryPatch(OPTIONS.input_tmp, output_sink, - # recovery_img, boot_img) - - system_items.GetMetadata(input_zip) - system_items.Get("system").SetPermissions(script) + script.FormatPartition("/data") - if HasVendorPartition(input_zip): - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - script.ShowProgress(0.1, 0) + script.Print("Formatting system...") + script.Unmount("/system") + script.FormatPartition("/system") - if block_based: - vendor_tgt = GetImage("vendor", OPTIONS.input_tmp, OPTIONS.info_dict) - vendor_tgt.ResetFileMap() - vendor_diff = common.BlockDifference("vendor", vendor_tgt) - vendor_diff.WriteScript(script, output_zip) - else: - script.FormatPartition("/vendor") - script.Mount("/vendor", recovery_mount_options) - script.UnpackPackageDir("vendor", "/vendor") + script.Print("Installing system files...") + script.Mount("/system") + #script.UnpackPackageDir("recovery", "/system") + script.UnpackPackageDir("system", "/system") - symlinks = CopyPartitionFiles(vendor_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) + script.Print("Creating system links...") + (symlinks, retouch_files) = CopySystemFiles(input_zip, output_zip) + script.MakeSymlinks(symlinks) + # if OPTIONS.aslr_mode: + # script.RetouchBinaries(retouch_files) + # else: + # script.UndoRetouchBinaries(retouch_files) - vendor_items.GetMetadata(input_zip) - vendor_items.Get("vendor").SetPermissions(script) + CopyDataFiles(input_zip, output_zip) - if HasCustPartition(input_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - script.ShowProgress(0.1, 0) - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - symlinks = CopyPartitionFiles(cust_items, input_zip, output_zip) - script.MakeSymlinks(symlinks) - cust_items.GetMetadata(input_zip) - cust_items.Get("cust").SetPermissions(script) + boot_img = common.GetBootableImage("boot.img", "boot.img", + OPTIONS.input_tmp, "BOOT") + # recovery_img = common.GetBootableImage("recovery.img", "recovery.img", + # OPTIONS.input_tmp, "RECOVERY") + # MakeRecoveryPatch(output_zip, recovery_img, boot_img) - #common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) - common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + script.Print("Set permission...") + Item.GetMetadata(input_zip) + Item.Get("system").SetPermissions(script) - script.ShowProgress(0.05, 5) - script.WriteRawImage("/boot", "boot.img") + script.Print("Update Boot image...") + if boot_img: + common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) + common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + script.ShowProgress(0.2, 0) script.ShowProgress(0.2, 10) + if boot_img and not device_specific.WriteRawImage("/boot", "boot.img"): + script.WriteRawImage("/boot", "boot.img") + + script.ShowProgress(0.1, 0) device_specific.FullOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) - script.UnmountAll() + script.Mount("/data") + script.UnpackPackageDir("data", "/data") + script.SetPermissionsRecursive("/data/preinstall_apps", 1000, 1000, 0755, 0644) + common.ZipWriteStr(output_zip, "data/preinstall_apps/reinstall_apps", "reinstall_apps") + script.AppendExtra('delete_recursive("/data/dalvik-cache");') - if OPTIONS.wipe_user_data: - script.ShowProgress(0.1, 10) - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -""" % bcb_dev) - script.AppendExtra("else\n") - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - script.AddToZip(input_zip, output_zip, input_path=OPTIONS.updater_binary) + script.UnmountAll() + script.AddToZip(input_zip, output_zip) WriteMetadata(metadata, output_zip) -def WritePolicyConfig(file_name, output_zip): - common.ZipWrite(output_zip, file_name, os.path.basename(file_name)) - - def WriteMetadata(metadata, output_zip): common.ZipWriteStr(output_zip, "META-INF/com/android/metadata", "".join(["%s=%s\n" % kv for kv in sorted(metadata.iteritems())])) -def LoadPartitionFiles(z, partition): - """Load all the files from the given partition in a given target-files + + +def LoadSystemFiles(z): + """Load all the files from SYSTEM/... in a given target-files ZipFile, and return a dict of {filename: File object}.""" out = {} - prefix = partition.upper() + "/" + retouch_files = [] for info in z.infolist(): - if info.filename.startswith(prefix) and not IsSymlink(info): - basefilename = info.filename[len(prefix):] - fn = partition + "/" + basefilename + if info.filename.startswith("SYSTEM/") and not IsSymlink(info): + basefilename = info.filename[7:] + fn = "system/" + basefilename data = z.read(info.filename) out[fn] = common.File(fn, data) - return out - - -def GetBuildProp(prop, info_dict): - """Return the fingerprint of the build of a given target-files info_dict.""" - try: - return info_dict.get("build.prop", {})[prop] - except KeyError: - raise common.ExternalError("couldn't find %s in build.prop" % (prop,)) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + out[fn].sha1)) + elif (info.filename.startswith("DATA/media/preinstall_apps") or info.filename.startswith("DATA/preinstall_apps")) and not IsSymlink(info): + basefilename = info.filename[5:] + fn = "data/" + basefilename + data = z.read(info.filename) + out[fn] = common.File(fn, data) + return (out, retouch_files) -def AddToKnownPaths(filename, known_paths): - if filename[-1] == "/": - return - dirs = filename.split("/")[:-1] - while len(dirs) > 0: - path = "/".join(dirs) - if path in known_paths: - break - known_paths.add(path) - dirs.pop() +def GetBuildProp(property, z): + """Return the fingerprint of the build of a given target-files + ZipFile object.""" + bp = z.read("SYSTEM/build.prop") + if not property: + return bp + m = re.search(re.escape(property) + r"=(.*)\n", bp) + if not m: + raise common.ExternalError("couldn't find %s in build.prop" % (property,)) + return m.group(1).strip() -def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): +def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): source_version = OPTIONS.source_info_dict["recovery_api_version"] target_version = OPTIONS.target_info_dict["recovery_api_version"] if source_version == 0: print ("WARNING: generating edify script for a source that " "can't install it.") - script = edify_generator.EdifyGenerator( - source_version, OPTIONS.target_info_dict, - fstab=OPTIONS.source_info_dict["fstab"]) + script = edify_generator.EdifyGenerator(source_version, OPTIONS.target_info_dict) - metadata = { - "pre-device": GetBuildProp("ro.product.device", - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } + metadata = {"pre-device": GetBuildProp("ro.product.device", source_zip), + "post-timestamp": GetBuildProp("ro.build.date.utc", target_zip), + } device_specific = common.DeviceSpecificParams( source_zip=source_zip, @@ -776,486 +525,66 @@ def WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip): metadata=metadata, info_dict=OPTIONS.info_dict) - # MIUI ADD: START - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - # END - - # TODO: Currently this works differently from WriteIncrementalOTAPackage(). - # This function doesn't consider thumbprints when writing - # metadata["pre/post-build"]. One possible reason is that the current - # devices with thumbprints are all using file-based OTAs. Long term we - # should factor out the common parts into a shared one to avoid further - # divergence. - source_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.source_info_dict) - target_fp = GetBuildProp("ro.build.fingerprint", OPTIONS.target_info_dict) - metadata["pre-build"] = source_fp - metadata["post-build"] = target_fp - - source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) - target_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) - - target_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") - - system_src = GetImage("system", OPTIONS.source_tmp, OPTIONS.source_info_dict) - system_tgt = GetImage("system", OPTIONS.target_tmp, OPTIONS.target_info_dict) - - blockimgdiff_version = 1 - if OPTIONS.info_dict: - blockimgdiff_version = max( - int(i) for i in - OPTIONS.info_dict.get("blockimgdiff_versions", "1").split(",")) - - system_diff = common.BlockDifference("system", system_tgt, system_src, - version=blockimgdiff_version) - - if HasVendorPartition(target_zip): - if not HasVendorPartition(source_zip): - raise RuntimeError("can't generate incremental that adds /vendor") - vendor_src = GetImage("vendor", OPTIONS.source_tmp, - OPTIONS.source_info_dict) - vendor_tgt = GetImage("vendor", OPTIONS.target_tmp, - OPTIONS.target_info_dict) - vendor_diff = common.BlockDifference("vendor", vendor_tgt, vendor_src, - version=blockimgdiff_version) - else: - vendor_diff = None - - oem_props = OPTIONS.target_info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.source_info_dict.get( - "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) - device_specific.IncrementalOTA_Assertions() - - # MIUI ADD: support cust - cust_diff = None - if HasCustPartition(target_zip): - if not HasCustPartition(source_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.FormatPartition("/cust") - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) + print "Loading target..." + (target_data, target_retouch_files) = LoadSystemFiles(target_zip) + print "Loading source..." + (source_data, source_retouch_files) = LoadSystemFiles(source_zip) + + verbatim_targets = [] + patch_list = [] + diffs = [] + largest_source_size = 0 + for fn in sorted(target_data.keys()): + tf = target_data[fn] + assert fn == tf.name + sf = source_data.get(fn, None) + + if sf is None or fn in OPTIONS.require_verbatim: + # This file should be included verbatim + if fn in OPTIONS.prohibit_verbatim: + raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) + print "send", fn, "verbatim" + tf.AddToZip(output_zip) + verbatim_targets.append((fn, tf.size)) + elif tf.sha1 != sf.sha1: + # File is different; consider sending as a patch + diffs.append(common.Difference(tf, sf)) else: - # cust_diff = FileDifference("cust", source_zip, target_zip, output_zip) - # script.Mount("/cust", recovery_mount_options) - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.source_info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.source_info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n") - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - # Dump fingerprints - script.Print("Source: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.source_info_dict)) - script.Print("Target: %s" % CalculateFingerprint( - oem_props, oem_dict, OPTIONS.target_info_dict)) - - script.Print("Verifying current system...") + # Target file identical to source. + pass - device_specific.IncrementalOTA_VerifyBegin() + common.ComputeDifferences(diffs) - if oem_props is None: - # When blockimgdiff version is less than 3 (non-resumable block-based OTA), - # patching on a device that's already on the target build will damage the - # system. Because operations like move don't check the block state, they - # always apply the changes unconditionally. - if blockimgdiff_version <= 2: - script.AssertSomeFingerprint(source_fp) - else: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - if blockimgdiff_version <= 2: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + for diff in diffs: + tf, sf, d = diff.GetPatch() + if d is None or len(d) > tf.size * OPTIONS.patch_threshold: + # patch is almost as big as the file; don't bother patching + tf.AddToZip(output_zip) + verbatim_targets.append((tf.name, tf.size)) else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) - - if updating_boot: - boot_type, boot_device = common.GetTypeAndDevice( - "/boot", OPTIONS.source_info_dict) - d = common.Difference(target_boot, source_boot) - _, _, d = d.ComputePatch() - if d is None: - include_full_boot = True - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - else: - include_full_boot = False - - print "boot target: %d source: %d diff: %d" % ( - target_boot.size, source_boot.size, len(d)) - - common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - - script.PatchCheck("%s:%s:%d:%s:%d:%s" % - (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1)) - - device_specific.IncrementalOTA_VerifyEnd() - - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - - # Verify the existing partitions. - system_diff.WriteVerifyScript(script) - if vendor_diff: - vendor_diff.WriteVerifyScript(script) - - script.Comment("---- start making changes here ----") - - device_specific.IncrementalOTA_InstallBegin() - - system_diff.WriteScript(script, output_zip, - progress=0.8 if vendor_diff else 0.9) - if vendor_diff: - vendor_diff.WriteScript(script, output_zip, progress=0.1) - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" - - if not OPTIONS.two_step: - if updating_boot: - if include_full_boot: - print "boot image changed; including full." - script.Print("Installing boot image...") - script.WriteRawImage("/boot", "boot.img") - else: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - print "boot image changed; including patch." - script.Print("Patching boot image...") - script.ShowProgress(0.1, 10) - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - else: - print "boot image unchanged; skipping." - - # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() - - if OPTIONS.extra_script is not None: - script.AppendExtra(OPTIONS.extra_script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") - - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - script.SetProgress(1) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) - WriteMetadata(metadata, output_zip) - - -class FileDifference(object): - def __init__(self, partition, source_zip, target_zip, output_zip): - self.deferred_patch_list = None - print "Loading target..." - self.target_data = target_data = LoadPartitionFiles(target_zip, partition) - print "Loading source..." - self.source_data = source_data = LoadPartitionFiles(source_zip, partition) - - self.verbatim_targets = verbatim_targets = [] - self.patch_list = patch_list = [] - diffs = [] - self.renames = renames = {} - known_paths = set() - largest_source_size = 0 - - matching_file_cache = {} - for fn, sf in source_data.items(): - assert fn == sf.name - matching_file_cache["path:" + fn] = sf - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - # Only allow eligibility for filename/sha matching - # if there isn't a perfect path match. - if target_data.get(sf.name) is None: - matching_file_cache["file:" + fn.split("/")[-1]] = sf - matching_file_cache["sha:" + sf.sha1] = sf - - for fn in sorted(target_data.keys()): - tf = target_data[fn] - assert fn == tf.name - # MIUI ADD: START - if fn.startswith("data/") and not fn.startswith("data/miui/"): - continue - # END - sf = ClosestFileMatch(tf, matching_file_cache, renames) - if sf is not None and sf.name != tf.name: - print "File has moved from " + sf.name + " to " + tf.name - renames[sf.name] = tf - - if sf is None or fn in OPTIONS.require_verbatim: - # This file should be included verbatim - if fn in OPTIONS.prohibit_verbatim: - raise common.ExternalError("\"%s\" must be sent verbatim" % (fn,)) - print "send", fn, "verbatim" - tf.AddToZip(output_zip) - verbatim_targets.append((fn, tf.size, tf.sha1)) - if fn in target_data.keys(): - AddToKnownPaths(fn, known_paths) - elif tf.sha1 != sf.sha1: - # File is different; consider sending as a patch - diffs.append(common.Difference(tf, sf)) - else: - # Target file data identical to source (may still be renamed) - pass - - common.ComputeDifferences(diffs) - - for diff in diffs: - tf, sf, d = diff.GetPatch() - path = "/".join(tf.name.split("/")[:-1]) - if d is None or len(d) > tf.size * OPTIONS.patch_threshold or \ - path not in known_paths: - # patch is almost as big as the file; don't bother patching - # or a patch + rename cannot take place due to the target - # directory not existing - tf.AddToZip(output_zip) - verbatim_targets.append((tf.name, tf.size, tf.sha1)) - if sf.name in renames: - del renames[sf.name] - AddToKnownPaths(tf.name, known_paths) - else: - common.ZipWriteStr(output_zip, "patch/" + sf.name + ".p", d) - patch_list.append((tf, sf, tf.size, common.sha1(d).hexdigest())) - largest_source_size = max(largest_source_size, sf.size) - - self.largest_source_size = largest_source_size - - def EmitVerification(self, script): - so_far = 0 - for tf, sf, _, _ in self.patch_list: - if tf.name != sf.name: - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.PatchCheck("/"+sf.name, tf.sha1, sf.sha1) - so_far += sf.size - return so_far - - def EmitExplicitTargetVerification(self, script): - for fn, _, sha1 in self.verbatim_targets: - if fn[-1] != "/": - script.FileCheck("/"+fn, sha1) - for tf, _, _, _ in self.patch_list: - script.FileCheck(tf.name, tf.sha1) - - def RemoveUnneededFiles(self, script, extras=()): - script.DeleteFiles( - ["/" + i[0] for i in self.verbatim_targets] + - ["/" + i for i in sorted(self.source_data) - if i not in self.target_data and i not in self.renames] + - list(extras)) - - def TotalPatchSize(self): - return sum(i[1].size for i in self.patch_list) - - def EmitPatches(self, script, total_patch_size, so_far): - self.deferred_patch_list = deferred_patch_list = [] - for item in self.patch_list: - tf, sf, _, _ = item - if tf.name == "system/build.prop": - deferred_patch_list.append(item) - continue - if sf.name != tf.name: - script.SkipNextActionIfTargetExists(tf.name, tf.sha1) - script.ApplyPatch("/" + sf.name, "-", tf.size, tf.sha1, sf.sha1, - "patch/" + sf.name + ".p") - so_far += tf.size - script.SetProgress(so_far / total_patch_size) - return so_far - - def EmitDeferredPatches(self, script): - for item in self.deferred_patch_list: - tf, sf, _, _ = item - script.ApplyPatch("/"+sf.name, "-", tf.size, tf.sha1, sf.sha1, - "patch/" + sf.name + ".p") - script.SetPermissions("/system/build.prop", 0, 0, 0o644, None, None) - - def EmitRenames(self, script): - if len(self.renames) > 0: - script.Print("Renaming files...") - for src, tgt in self.renames.iteritems(): - print "Renaming " + src + " to " + tgt.name - script.RenameFile(src, tgt.name) - - -def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): - target_has_recovery_patch = HasRecoveryPatch(target_zip) - source_has_recovery_patch = HasRecoveryPatch(source_zip) - - if (OPTIONS.block_based and - target_has_recovery_patch and - source_has_recovery_patch): - return WriteBlockIncrementalOTAPackage(target_zip, source_zip, output_zip) - - source_version = OPTIONS.source_info_dict["recovery_api_version"] - target_version = OPTIONS.target_info_dict["recovery_api_version"] - - if source_version == 0: - print ("WARNING: generating edify script for a source that " - "can't install it.") - script = edify_generator.EdifyGenerator( - source_version, OPTIONS.target_info_dict, - fstab=OPTIONS.source_info_dict["fstab"]) - - oem_props = OPTIONS.info_dict.get("oem_fingerprint_properties") - recovery_mount_options = OPTIONS.source_info_dict.get( - "recovery_mount_options") - oem_dict = None - if oem_props is not None and len(oem_props) > 0: - if OPTIONS.oem_source is None: - raise common.ExternalError("OEM source required for this build") - script.Mount("/oem", recovery_mount_options) - oem_dict = common.LoadDictionaryFromLines( - open(OPTIONS.oem_source).readlines()) - - metadata = { - "pre-device": GetOemProperty("ro.product.device", oem_props, oem_dict, - OPTIONS.source_info_dict), - "post-timestamp": GetBuildProp("ro.build.date.utc", - OPTIONS.target_info_dict), - } - - device_specific = common.DeviceSpecificParams( - source_zip=source_zip, - source_version=source_version, - target_zip=target_zip, - target_version=target_version, - output_zip=output_zip, - script=script, - metadata=metadata, - info_dict=OPTIONS.info_dict) - - # MIUI ADD: - data_diff = FileDifference("data", source_zip, target_zip, output_zip) - - # MIUI ADD: START - if "selinux_fc" in OPTIONS.info_dict: - WritePolicyConfig(OPTIONS.info_dict["selinux_fc"], output_zip) - # END - - system_diff = FileDifference("system", source_zip, target_zip, output_zip) - script.Mount("/system", recovery_mount_options) - if HasVendorPartition(target_zip): - vendor_diff = FileDifference("vendor", source_zip, target_zip, output_zip) - script.Mount("/vendor", recovery_mount_options) - else: - vendor_diff = None - - target_fp = CalculateFingerprint(oem_props, oem_dict, - OPTIONS.target_info_dict) - source_fp = CalculateFingerprint(oem_props, oem_dict, - OPTIONS.source_info_dict) - - if oem_props is None: - script.AssertSomeFingerprint(source_fp, target_fp) - else: - script.AssertSomeThumbprint( - GetBuildProp("ro.build.thumbprint", OPTIONS.target_info_dict), - GetBuildProp("ro.build.thumbprint", OPTIONS.source_info_dict)) + common.ZipWriteStr(output_zip, "patch/" + tf.name + ".p", d) + patch_list.append((tf.name, tf, sf, tf.size, common.sha1(d).hexdigest())) + largest_source_size = max(largest_source_size, sf.size) + source_fp = GetBuildProp("ro.build.fingerprint", source_zip) + target_fp = GetBuildProp("ro.build.fingerprint", target_zip) metadata["pre-build"] = source_fp metadata["post-build"] = target_fp + script.Mount("/system") + script.Mount("/data") + script.AssertSomeFingerprint(source_fp, target_fp) + source_boot = common.GetBootableImage( - "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT", - OPTIONS.source_info_dict) + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT") target_boot = common.GetBootableImage( "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") - updating_boot = (not OPTIONS.two_step and - (source_boot.data != target_boot.data)) + # updating_boot = (source_boot != None and target_boot != None and source_boot.data != target_boot.data) + updating_boot = False + need_install_boot = (source_boot != None and target_boot != None and source_boot.data != target_boot.data) source_recovery = common.GetBootableImage( - "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY", - OPTIONS.source_info_dict) + "/tmp/recovery.img", "recovery.img", OPTIONS.source_tmp, "RECOVERY") target_recovery = common.GetBootableImage( "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") updating_recovery = (source_recovery.data != target_recovery.data) @@ -1266,85 +595,24 @@ def WriteIncrementalOTAPackage(target_zip, source_zip, output_zip): # 0.1 for unpacking verbatim files, symlinking, and doing the # device-specific commands. - AppendAssertions(script, OPTIONS.target_info_dict, oem_dict) + AppendAssertions(script, target_zip) device_specific.IncrementalOTA_Assertions() - # MIUI ADD - cust_diff = None - if HasCustPartition(target_zip): - if not HasCustPartition(source_zip): - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") - - script.FormatPartition("/cust") - script.Mount("/cust", recovery_mount_options) - script.UnpackPackageDir("cust", "/cust") - - symlinks = CopyPartitionFiles(cust_items, target_zip, output_zip) - script.MakeSymlinks(symlinks) - - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(script) - else: - cust_diff = FileDifference("cust", source_zip, target_zip, output_zip) - script.Mount("/cust", recovery_mount_options) - - # Two-step incremental package strategy (in chronological order, - # which is *not* the order in which the generated script has - # things): - # - # if stage is not "2/3" or "3/3": - # do verification on current system - # write recovery image to boot partition - # set stage to "2/3" - # reboot to boot partition and restart recovery - # else if stage is "2/3": - # write recovery image to recovery partition - # set stage to "3/3" - # reboot to recovery partition and restart recovery - # else: - # (stage must be "3/3") - # perform update: - # patch system files, etc. - # force full install of new boot image - # set up system to update recovery partition on first boot - # complete script normally - # (allow recovery to mark itself finished and reboot) - - if OPTIONS.two_step: - if not OPTIONS.source_info_dict.get("multistage_support", None): - assert False, "two-step packages not supported by this build" - fs = OPTIONS.source_info_dict["fstab"]["/misc"] - assert fs.fs_type.upper() == "EMMC", \ - "two-step packages only supported on devices with EMMC /misc partitions" - bcb_dev = {"bcb_dev": fs.device} - common.ZipWriteStr(output_zip, "recovery.img", target_recovery.data) - script.AppendExtra(""" -if get_stage("%(bcb_dev)s") == "2/3" then -""" % bcb_dev) - script.AppendExtra("sleep(20);\n") - script.WriteRawImage("/recovery", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "3/3"); -reboot_now("%(bcb_dev)s", "recovery"); -else if get_stage("%(bcb_dev)s") != "3/3" then -""" % bcb_dev) - - # Dump fingerprints - script.Print("Source: %s" % (source_fp,)) - script.Print("Target: %s" % (target_fp,)) - + script.AppendExtra('delete_recursive("/data/dalvik-cache");') script.Print("Verifying current system...") - device_specific.IncrementalOTA_VerifyBegin() - script.ShowProgress(0.1, 0) - so_far = system_diff.EmitVerification(script) - if vendor_diff: - so_far += vendor_diff.EmitVerification(script) + total_verify_size = float(sum([i[2].size for i in patch_list]) + 1) + if updating_boot: + total_verify_size += source_boot.size + so_far = 0 - # MIUI ADD - if cust_diff: - so_far += cust_diff.EmitVerification(script) + for fn, tf, sf, size, patch_sha in patch_list: + if fn.startswith("data/"): + continue + script.PatchCheck("/"+fn, tf.sha1, sf.sha1) + so_far += sf.size + script.SetProgress(so_far / total_verify_size) if updating_boot: d = common.Difference(target_boot, source_boot) @@ -1354,216 +622,130 @@ else if get_stage("%(bcb_dev)s") != "3/3" then common.ZipWriteStr(output_zip, "patch/boot.img.p", d) - boot_type, boot_device = common.GetTypeAndDevice( - "/boot", OPTIONS.source_info_dict) + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) script.PatchCheck("%s:%s:%d:%s:%d:%s" % (boot_type, boot_device, source_boot.size, source_boot.sha1, target_boot.size, target_boot.sha1)) so_far += source_boot.size + script.SetProgress(so_far / total_verify_size) - size = [] - if system_diff.patch_list: - size.append(system_diff.largest_source_size) - if vendor_diff: - if vendor_diff.patch_list: - size.append(vendor_diff.largest_source_size) - # MIUI ADD - if cust_diff: - if cust_diff.patch_list: - size.append(cust_diff.largest_source_size) - - if size or updating_recovery or updating_boot: - script.CacheFreeSpaceCheck(max(size)) + if patch_list or updating_recovery or updating_boot: + script.CacheFreeSpaceCheck(largest_source_size) device_specific.IncrementalOTA_VerifyEnd() - if OPTIONS.two_step: - script.WriteRawImage("/boot", "recovery.img") - script.AppendExtra(""" -set_stage("%(bcb_dev)s", "2/3"); -reboot_now("%(bcb_dev)s", ""); -else -""" % bcb_dev) - script.Comment("---- start making changes here ----") - device_specific.IncrementalOTA_InstallBegin() - - if OPTIONS.two_step: - common.ZipWriteStr(output_zip, "boot.img", target_boot.data) - script.WriteRawImage("/boot", "boot.img") - print "writing full boot image (forced by two-step mode)" + if OPTIONS.wipe_user_data: + script.Print("Erasing user data...") + script.FormatPartition("/data") script.Print("Removing unneeded files...") - system_diff.RemoveUnneededFiles(script, ("/system/recovery.img",)) - if vendor_diff: - vendor_diff.RemoveUnneededFiles(script) - # MIUI ADD - if cust_diff: - cust_diff.RemoveUnneededFiles(script) + script.DeleteFiles(["/"+i[0] for i in verbatim_targets] + + ["/"+i for i in sorted(source_data) + if i not in target_data] + + ["/system/recovery.img"]) script.ShowProgress(0.8, 0) - total_patch_size = 1.0 + system_diff.TotalPatchSize() - if vendor_diff: - total_patch_size += vendor_diff.TotalPatchSize() - # MIUI ADD - if cust_diff: - total_patch_size += cust_diff.TotalPatchSize() - + total_patch_size = float(sum([i[1].size for i in patch_list]) + 1) if updating_boot: total_patch_size += target_boot.size + so_far = 0 script.Print("Patching system files...") - so_far = system_diff.EmitPatches(script, total_patch_size, 0) - if vendor_diff: - script.Print("Patching vendor files...") - so_far = vendor_diff.EmitPatches(script, total_patch_size, so_far) - # MIUI ADD - if cust_diff: - script.Print("Patching cust files...") - so_far = cust_diff.EmitPatches(script, total_patch_size, so_far) - - - if not OPTIONS.two_step: - if updating_boot: - # Produce the boot image by applying a patch to the current - # contents of the boot partition, and write it back to the - # partition. - script.Print("Patching boot image...") - script.ApplyPatch("%s:%s:%d:%s:%d:%s" - % (boot_type, boot_device, - source_boot.size, source_boot.sha1, - target_boot.size, target_boot.sha1), - "-", - target_boot.size, target_boot.sha1, - source_boot.sha1, "patch/boot.img.p") - so_far += target_boot.size - script.SetProgress(so_far / total_patch_size) - print "boot image changed; including." - else: - print "boot image unchanged; skipping." + deferred_patch_list = [] + for item in patch_list: + fn, tf, sf, size, _ = item + if tf.name == "system/build.prop": + deferred_patch_list.append(item) + continue + script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") + so_far += tf.size + script.SetProgress(so_far / total_patch_size) - system_items = ItemSet("system", "META/filesystem_config.txt") - if vendor_diff: - vendor_items = ItemSet("vendor", "META/vendor_filesystem_config.txt") - # MIUI ADD - if cust_diff: - cust_items = ItemSet("cust", "META/cust_filesystem_config.txt") + if updating_boot: + # Produce the boot image by applying a patch to the current + # contents of the boot partition, and write it back to the + # partition. + script.Print("Patching boot image...") + script.ApplyPatch("%s:%s:%d:%s:%d:%s" + % (boot_type, boot_device, + source_boot.size, source_boot.sha1, + target_boot.size, target_boot.sha1), + "-", + target_boot.size, target_boot.sha1, + source_boot.sha1, "patch/boot.img.p") + so_far += target_boot.size + script.SetProgress(so_far / total_patch_size) + print "boot image changed; including." + else: + print "boot image unchanged; skipping." + + if need_install_boot: + boot_img = common.GetBootableImage("boot.img", "boot.img", + OPTIONS.input_tmp, "BOOT") + script.Print("Update Boot image...") + if boot_img: + common.CheckSize(boot_img.data, "boot.img", OPTIONS.info_dict) + common.ZipWriteStr(output_zip, "boot.img", boot_img.data) + if boot_img and not device_specific.WriteRawImage("/boot", "boot.img"): + script.WriteRawImage("/boot", "boot.img") if updating_recovery: - # Recovery is generated as a patch using both the boot image - # (which contains the same linux kernel as recovery) and the file - # /system/etc/recovery-resource.dat (which contains all the images - # used in the recovery UI) as sources. This lets us minimize the - # size of the patch, which must be included in every OTA package. + # Is it better to generate recovery as a patch from the current + # boot image, or from the previous recovery image? For large + # updates with significant kernel changes, probably the former. + # For small updates where the kernel hasn't changed, almost + # certainly the latter. We pick the first option. Future + # complicated schemes may let us effectively use both. # - # For older builds where recovery-resource.dat is not present, we - # use only the boot image as the source. - - if not target_has_recovery_patch: - def output_sink(fn, data): - common.ZipWriteStr(output_zip, "recovery/" + fn, data) - system_items.Get("system/" + fn) - - common.MakeRecoveryPatch(OPTIONS.target_tmp, output_sink, - target_recovery, target_boot) - script.DeleteFiles(["/system/recovery-from-boot.p", - "/system/etc/install-recovery.sh"]) + # A wacky possibility: as long as there is room in the boot + # partition, include the binaries and image files from recovery in + # the boot image (though not in the ramdisk) so they can be used + # as fodder for constructing the recovery image. + MakeRecoveryPatch(output_zip, target_recovery, target_boot) + script.DeleteFiles(["/system/recovery-from-boot.p", + "/system/etc/install-recovery.sh"]) print "recovery image changed; including as patch from boot." else: print "recovery image unchanged; skipping." script.ShowProgress(0.1, 10) - target_symlinks = CopyPartitionFiles(system_items, target_zip, None) - if vendor_diff: - target_symlinks.extend(CopyPartitionFiles(vendor_items, target_zip, None)) - # MIUI ADD - if cust_diff: - target_symlinks.extend(CopyPartitionFiles(cust_items, target_zip, None)) + (target_symlinks, target_retouch_dummies) = CopySystemFiles(target_zip, None) + target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) temp_script = script.MakeTemporary() - system_items.GetMetadata(target_zip) - system_items.Get("system").SetPermissions(temp_script) - if vendor_diff: - vendor_items.GetMetadata(target_zip) - vendor_items.Get("vendor").SetPermissions(temp_script) - # MIUI ADD - if cust_diff: - cust_items.GetMetadata(target_zip) - cust_items.Get("cust").SetPermissions(temp_script) - - # Note that this call will mess up the trees of Items, so make sure - # we're done with them. - source_symlinks = CopyPartitionFiles(system_items, source_zip, None) - if vendor_diff: - source_symlinks.extend(CopyPartitionFiles(vendor_items, source_zip, None)) - # MIUI ADD - if cust_diff: - source_symlinks.extend(CopyPartitionFiles(cust_items, source_zip, None)) + Item.GetMetadata(target_zip) + Item.Get("system").SetPermissions(temp_script) - target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) + # Note that this call will mess up the tree of Items, so make sure + # we're done with it. + (source_symlinks, source_retouch_dummies) = CopySystemFiles(source_zip, None) source_symlinks_d = dict([(i[1], i[0]) for i in source_symlinks]) # Delete all the symlinks in source that aren't in target. This # needs to happen before verbatim files are unpacked, in case a # symlink in the source is replaced by a real file in the target. - - # If a symlink in the source will be replaced by a regular file, we cannot - # delete the symlink/file in case the package gets applied again. For such - # a symlink, we prepend a sha1_check() to detect if it has been updated. - # (Bug: 23646151) - replaced_symlinks = dict() - if system_diff: - for i in system_diff.verbatim_targets: - replaced_symlinks["/%s" % (i[0],)] = i[2] - if vendor_diff: - for i in vendor_diff.verbatim_targets: - replaced_symlinks["/%s" % (i[0],)] = i[2] - - if system_diff: - for tf in system_diff.renames.values(): - replaced_symlinks["/%s" % (tf.name,)] = tf.sha1 - if vendor_diff: - for tf in vendor_diff.renames.values(): - replaced_symlinks["/%s" % (tf.name,)] = tf.sha1 - - always_delete = [] - may_delete = [] + to_delete = [] for dest, link in source_symlinks: if link not in target_symlinks_d: - if link in replaced_symlinks: - may_delete.append((link, replaced_symlinks[link])) - else: - always_delete.append(link) - script.DeleteFiles(always_delete) - script.DeleteFilesIfNotMatching(may_delete) + to_delete.append(link) + script.DeleteFiles(to_delete) - if system_diff.verbatim_targets: - script.Print("Unpacking new system files...") + if verbatim_targets: + script.Print("Unpacking new files...") script.UnpackPackageDir("system", "/system") - if vendor_diff and vendor_diff.verbatim_targets: - script.Print("Unpacking new vendor files...") - script.UnpackPackageDir("vendor", "/vendor") - # MIUI ADD - if cust_diff and cust_diff.verbatim_targets: - script.Print("Unpacking new cust files...") - script.UnpackPackageDir("cust", "/cust") - - if updating_recovery and not target_has_recovery_patch: + script.UnpackPackageDir("data", "/data") + + if updating_recovery: script.Print("Unpacking new recovery...") script.UnpackPackageDir("recovery", "/system") - system_diff.EmitRenames(script) - if vendor_diff: - vendor_diff.EmitRenames(script) - # MIUI ADD - if cust_diff: - cust_diff.EmitRenames(script) - script.Print("Symlinks and permissions...") + script.SetPermissionsRecursive("/data/preinstall_apps", 1000, 1000, 0755, 0644) # Create all the symlinks that don't already exist, or point to # somewhere different than what we want. Delete each symlink before @@ -1577,13 +759,16 @@ else to_create.append((dest, link)) script.DeleteFiles([i[1] for i in to_create]) script.MakeSymlinks(to_create) + # if OPTIONS.aslr_mode: + # script.RetouchBinaries(target_retouch_files) + # else: + # script.UndoRetouchBinaries(target_retouch_files) # Now that the symlinks are created, we can set all the # permissions. script.AppendScript(temp_script) # Do device-specific installation (eg, write radio image). - device_specific.IncrementalOTA_InstallEnd() if OPTIONS.extra_script is not None: script.AppendExtra(OPTIONS.extra_script) @@ -1592,52 +777,31 @@ else # device can still come up, it appears to be the old build and will # get set the OTA package again to retry. script.Print("Patching remaining system files...") - system_diff.EmitDeferredPatches(script) - - if OPTIONS.wipe_user_data: - script.Print("Erasing user data...") - script.FormatPartition("/data") + for item in deferred_patch_list: + fn, tf, sf, size, _ = item + script.ApplyPatch("/"+fn, "-", tf.size, tf.sha1, sf.sha1, "patch/"+fn+".p") + + device_specific.IncrementalOTA_InstallEnd() - if OPTIONS.two_step: - script.AppendExtra(""" -set_stage("%(bcb_dev)s", ""); -endif; -endif; -""" % bcb_dev) - - if OPTIONS.verify and system_diff: - script.Print("Remounting and verifying system partition files...") - script.Unmount("/system") - script.Mount("/system") - system_diff.EmitExplicitTargetVerification(script) - - if OPTIONS.verify and vendor_diff: - script.Print("Remounting and verifying vendor partition files...") - script.Unmount("/vendor") - script.Mount("/vendor") - vendor_diff.EmitExplicitTargetVerification(script) - script.AddToZip(target_zip, output_zip, input_path=OPTIONS.updater_binary) + script.SetPermissions("/system/build.prop", 0, 0, 0644) + script.AddToZip(target_zip, output_zip) WriteMetadata(metadata, output_zip) def main(argv): def option_handler(o, a): - if o == "--board_config": + if o in ("-b", "--board_config"): pass # deprecated elif o in ("-k", "--package_key"): OPTIONS.package_key = a elif o in ("-i", "--incremental_from"): OPTIONS.incremental_source = a - elif o == "--full_radio": - OPTIONS.full_radio = True elif o in ("-w", "--wipe_user_data"): OPTIONS.wipe_user_data = True elif o in ("-n", "--no_prereq"): OPTIONS.omit_prereq = True - elif o in ("-o", "--oem_settings"): - OPTIONS.oem_source = a elif o in ("-e", "--extra_script"): OPTIONS.extra_script = a elif o in ("-a", "--aslr_mode"): @@ -1645,48 +809,24 @@ def main(argv): OPTIONS.aslr_mode = True else: OPTIONS.aslr_mode = False - elif o in ("-t", "--worker_threads"): - if a.isdigit(): - OPTIONS.worker_threads = int(a) - else: - raise ValueError("Cannot parse value %r for option %r - only " - "integers are allowed." % (a, o)) - elif o in ("-2", "--two_step"): - OPTIONS.two_step = True - elif o == "--no_signing": - OPTIONS.no_signing = True - elif o == "--verify": - OPTIONS.verify = True - elif o == "--block": - OPTIONS.block_based = True - elif o in ("-b", "--binary"): - OPTIONS.updater_binary = a - elif o in ("--no_fallback_to_full",): - OPTIONS.fallback_to_full = False + elif o in ("--worker_threads"): + OPTIONS.worker_threads = int(a) else: return False return True args = common.ParseOptions(argv, __doc__, - extra_opts="b:k:i:d:wne:t:a:2o:", - extra_long_opts=[ - "board_config=", - "package_key=", - "incremental_from=", - "full_radio", - "wipe_user_data", - "no_prereq", - "extra_script=", - "worker_threads=", - "aslr_mode=", - "two_step", - "no_signing", - "block", - "binary=", - "oem_settings=", - "verify", - "no_fallback_to_full", - ], extra_option_handler=option_handler) + extra_opts="b:k:i:d:wne:a:", + extra_long_opts=["board_config=", + "package_key=", + "incremental_from=", + "wipe_user_data", + "no_prereq", + "extra_script=", + "worker_threads=", + "aslr_mode=", + ], + extra_option_handler=option_handler) if len(args) != 2: common.Usage(__doc__) @@ -1700,88 +840,46 @@ def main(argv): OPTIONS.target_tmp = OPTIONS.input_tmp OPTIONS.info_dict = common.LoadInfoDict(input_zip) - - # If this image was originally labelled with SELinux contexts, make sure we - # also apply the labels in our new image. During building, the "file_contexts" - # is in the out/ directory tree, but for repacking from target-files.zip it's - # in the root directory of the ramdisk. - if "selinux_fc" in OPTIONS.info_dict: - OPTIONS.info_dict["selinux_fc"] = os.path.join( - OPTIONS.input_tmp, "BOOT", "RAMDISK", "file_contexts") - if OPTIONS.verbose: print "--- target info ---" common.DumpInfoDict(OPTIONS.info_dict) - # If the caller explicitly specified the device-specific extensions - # path via -s/--device_specific, use that. Otherwise, use - # META/releasetools.py if it is present in the target target_files. - # Otherwise, take the path of the file from 'tool_extensions' in the - # info dict and look for that in the local filesystem, relative to - # the current directory. - if OPTIONS.device_specific is None: - from_input = os.path.join(OPTIONS.input_tmp, "META", "releasetools.py") - if os.path.exists(from_input): - print "(using device-specific extensions from target_files)" - OPTIONS.device_specific = from_input - else: - OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) - + OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) if OPTIONS.device_specific is not None: - OPTIONS.device_specific = os.path.abspath(OPTIONS.device_specific) - - while True: - - if OPTIONS.no_signing: - if os.path.exists(args[1]): - os.unlink(args[1]) - output_zip = zipfile.ZipFile(args[1], "w", - compression=zipfile.ZIP_DEFLATED) - else: - temp_zip_file = tempfile.NamedTemporaryFile() - output_zip = zipfile.ZipFile(temp_zip_file, "w", - compression=zipfile.ZIP_DEFLATED) - - if OPTIONS.incremental_source is None: - WriteFullOTAPackage(input_zip, output_zip) - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - common.ZipClose(output_zip) - break - - else: - print "unzipping source target-files..." - OPTIONS.source_tmp, source_zip = common.UnzipTemp( - OPTIONS.incremental_source) - OPTIONS.target_info_dict = OPTIONS.info_dict - OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) - if "selinux_fc" in OPTIONS.source_info_dict: - OPTIONS.source_info_dict["selinux_fc"] = os.path.join( - OPTIONS.source_tmp, "BOOT", "RAMDISK", "file_contexts") - if OPTIONS.package_key is None: - OPTIONS.package_key = OPTIONS.source_info_dict.get( - "default_system_dev_certificate", - "build/target/product/security/testkey") - if OPTIONS.verbose: - print "--- source info ---" - common.DumpInfoDict(OPTIONS.source_info_dict) - try: - WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) - common.ZipClose(output_zip) - break - except ValueError: - if not OPTIONS.fallback_to_full: - raise - print "--- failed to build incremental; falling back to full ---" - OPTIONS.incremental_source = None - common.ZipClose(output_zip) - - if not OPTIONS.no_signing: - SignOutput(temp_zip_file.name, args[1]) - temp_zip_file.close() + OPTIONS.device_specific = os.path.normpath(OPTIONS.device_specific) + print "using device-specific extensions in", OPTIONS.device_specific + + temp_zip_file = tempfile.NamedTemporaryFile() + output_zip = zipfile.ZipFile(temp_zip_file, "w", + compression=zipfile.ZIP_DEFLATED) + + if OPTIONS.incremental_source is None: + WriteFullOTAPackage(input_zip, output_zip) + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + else: + print "unzipping source target-files..." + OPTIONS.source_tmp, source_zip = common.UnzipTemp(OPTIONS.incremental_source) + OPTIONS.target_info_dict = OPTIONS.info_dict + OPTIONS.source_info_dict = common.LoadInfoDict(source_zip) + if OPTIONS.package_key is None: + OPTIONS.package_key = OPTIONS.source_info_dict.get( + "default_system_dev_certificate", + "build/target/product/security/testkey") + if OPTIONS.verbose: + print "--- source info ---" + common.DumpInfoDict(OPTIONS.source_info_dict) + WriteIncrementalOTAPackage(input_zip, source_zip, output_zip) + + output_zip.close() + + SignOutput(temp_zip_file.name, args[1]) + temp_zip_file.close() + + common.Cleanup() print "done." @@ -1790,10 +888,8 @@ if __name__ == '__main__': try: common.CloseInheritedPipes() main(sys.argv[1:]) - except common.ExternalError as e: + except common.ExternalError, e: print print " ERROR: %s" % (e,) print sys.exit(1) - finally: - common.Cleanup() diff --git a/releasetools/ota_target_from_phone b/releasetools/ota_target_from_phone index 218d02d..677b5d7 100755 --- a/releasetools/ota_target_from_phone +++ b/releasetools/ota_target_from_phone @@ -170,46 +170,28 @@ function build_apkcerts { # build filesystem_config.txt from device function build_filesystem_config { echo "Run getfilesysteminfo to build filesystem_config.txt" - if [ $ANDROID_PLATFORM -gt 19 ];then - adb push $TOOL_DIR/target_files_template/OTA/bin/busybox /data/local/tmp/ - adb shell chmod 755 /data/local/tmp/busybox - bash $TOOL_DIR/get_filesystem_config --info /data/local/tmp/busybox | tee $META_DIR/filesystem_config.txt - if [ $? -ne 0 ];then - echo "Get file info failed" - exit 1 - fi - else - adb push $TOOL_DIR/releasetools/getfilesysteminfo /system/xbin - adb shell chmod 0777 /system/xbin/getfilesysteminfo - adb shell /system/xbin/getfilesysteminfo --info /system >> $META_DIR/filesystem_config.txt - fs_config=`cat $META_DIR/filesystem_config.txt | col -b | sed -e '/getfilesysteminfo/d'` - OLD_IFS=$IFS - IFS=$'\n' - for line in $fs_config - do - echo $line | grep -q -e "\" && continue - echo $line | grep -q -e "\" && continue - echo $line >> $META_DIR/tmp.txt - done - IFS=$OLD_IFS - cat $META_DIR/tmp.txt | sort > $META_DIR/filesystem_config.txt - rm $META_DIR/tmp.txt - fi + + adb push $TOOL_DIR/releasetools/getfilesysteminfo /system/xbin + adb shell chmod 0777 /system/xbin/getfilesysteminfo + adb shell /system/xbin/getfilesysteminfo --info /system >> $META_DIR/filesystem_config.txt + fs_config=`cat $META_DIR/filesystem_config.txt | col -b | sed -e '/getfilesysteminfo/d'` + OLD_IFS=$IFS + IFS=$'\n' + for line in $fs_config + do + echo $line | grep -q -e "\" && continue + echo $line | grep -q -e "\" && continue + echo $line >> $META_DIR/tmp.txt + done + IFS=$OLD_IFS + cat $META_DIR/tmp.txt | sort > $META_DIR/filesystem_config.txt + rm $META_DIR/tmp.txt } # recover the device files' symlink information function recover_symlink { echo "Run getfilesysteminfo and recoverylink.py to recover symlink" - if [ $ANDROID_PLATFORM -gt 19 ];then - bash $TOOL_DIR/get_filesystem_config --link /data/local/tmp/busybox | tee $SYSTEM_DIR/linkinfo.txt - if [ $? -ne 0 ];then - echo "Get file symlink failed" - exit 1 - fi - else - adb shell /system/xbin/getfilesysteminfo --link /system | sed -e '/\/d;/\/d' | sort > $SYSTEM_DIR/linkinfo.txt - adb shell rm /system/xbin/getfilesysteminfo - fi + adb shell /system/xbin/getfilesysteminfo --link /system | sed -e '/\/d;/\/d' | sort > $SYSTEM_DIR/linkinfo.txt python $TOOL_DIR/releasetools/recoverylink.py $TARGET_FILES_DIR adb shell rm /system/xbin/getfilesysteminfo } @@ -260,14 +242,6 @@ function build_SYSTEM { recover_symlink } -function deoat { - if [ $ANDROID_PLATFORM -le 19 ];then - return - fi - echo "Decode oat files" - $TOOL_DIR/deoat.sh $TARGET_FILES_DIR -} - # compress the target_files dir into a zip file function zip_target_files { echo "Compress the target_files dir into zip file" @@ -321,7 +295,6 @@ fi build_SYSTEM build_apkcerts gen_metadata -deoat zip_target_files build_ota_package diff --git a/releasetools/pylintrc b/releasetools/pylintrc deleted file mode 100644 index 90de1af..0000000 --- a/releasetools/pylintrc +++ /dev/null @@ -1,382 +0,0 @@ -[MASTER] - -# Specify a configuration file. -#rcfile= - -# Python code to execute, usually for sys.path manipulation such as -# pygtk.require(). -#init-hook= - -# Profiled execution. -profile=no - -# Add files or directories to the blacklist. They should be base names, not -# paths. -ignore=CVS - -# Pickle collected data for later comparisons. -persistent=yes - -# List of plugins (as comma separated values of python modules names) to load, -# usually to register additional checkers. -load-plugins= - -# Use multiple processes to speed up Pylint. -jobs=1 - -# Allow loading of arbitrary C extensions. Extensions are imported into the -# active Python interpreter and may run arbitrary code. -unsafe-load-any-extension=no - -# A comma-separated list of package or module names from where C extensions may -# be loaded. Extensions are loading into the active Python interpreter and may -# run arbitrary code -extension-pkg-whitelist= - -# Allow optimization of some AST trees. This will activate a peephole AST -# optimizer, which will apply various small optimizations. For instance, it can -# be used to obtain the result of joining multiple strings with the addition -# operator. Joining a lot of strings can lead to a maximum recursion error in -# Pylint and this flag can prevent that. It has one side effect, the resulting -# AST will be different than the one from reality. -optimize-ast=no - - -[MESSAGES CONTROL] - -# Only show warnings with the listed confidence levels. Leave empty to show -# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED -confidence= - -# Enable the message, report, category or checker with the given id(s). You can -# either give multiple identifier separated by comma (,) or put this option -# multiple time. See also the "--disable" option for examples. -#enable= - -# Disable the message, report, category or checker with the given id(s). You -# can either give multiple identifiers separated by comma (,) or put this -# option multiple times (only on the command line, not in the configuration -# file where it should appear only once).You can also use "--disable=all" to -# disable everything first and then reenable specific checks. For example, if -# you want to run only the similarities checker, you can use "--disable=all -# --enable=similarities". If you want to run only the classes checker, but have -# no Warning level messages displayed, use"--disable=all --enable=classes -# --disable=W" -disable=invalid-name,missing-docstring,too-many-branches,too-many-locals,too-many-arguments,too-many-statements,duplicate-code,too-few-public-methods,too-many-instance-attributes,too-many-lines,too-many-public-methods,locally-disabled,fixme - - -[REPORTS] - -# Set the output format. Available formats are text, parseable, colorized, msvs -# (visual studio) and html. You can also give a reporter class, eg -# mypackage.mymodule.MyReporterClass. -output-format=text - -# Put messages in a separate file for each module / package specified on the -# command line instead of printing them on stdout. Reports (if any) will be -# written in a file name "pylint_global.[txt|html]". -files-output=no - -# Tells whether to display a full report or only the messages -reports=yes - -# Python expression which should return a note less than 10 (10 is the highest -# note). You have access to the variables errors warning, statement which -# respectively contain the number of errors / warnings messages and the total -# number of statements analyzed. This is used by the global evaluation report -# (RP0004). -evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) - -# Add a comment according to your evaluation note. This is used by the global -# evaluation report (RP0004). -comment=no - -# Template used to display messages. This is a python new-style format string -# used to format the message information. See doc for all details -#msg-template= - - -[SIMILARITIES] - -# Minimum lines number of a similarity. -min-similarity-lines=4 - -# Ignore comments when computing similarities. -ignore-comments=yes - -# Ignore docstrings when computing similarities. -ignore-docstrings=yes - -# Ignore imports when computing similarities. -ignore-imports=no - - -[TYPECHECK] - -# Tells whether missing members accessed in mixin class should be ignored. A -# mixin class is detected if its name ends with "mixin" (case insensitive). -ignore-mixin-members=yes - -# List of module names for which member attributes should not be checked -# (useful for modules/projects where namespaces are manipulated during runtime -# and thus existing member attributes cannot be deduced by static analysis -ignored-modules= - -# List of classes names for which member attributes should not be checked -# (useful for classes with attributes dynamically set). -ignored-classes=SQLObject - -# When zope mode is activated, add a predefined set of Zope acquired attributes -# to generated-members. -zope=no - -# List of members which are set dynamically and missed by pylint inference -# system, and so shouldn't trigger E0201 when accessed. Python regular -# expressions are accepted. -generated-members=REQUEST,acl_users,aq_parent - - -[MISCELLANEOUS] - -# List of note tags to take in consideration, separated by a comma. -notes=FIXME,XXX,TODO - - -[BASIC] - -# Required attributes for module, separated by a comma -required-attributes= - -# List of builtins function names that should not be used, separated by a comma -bad-functions=map,filter,input - -# Good variable names which should always be accepted, separated by a comma -good-names=i,j,k,ex,Run,_ - -# Bad variable names which should always be refused, separated by a comma -bad-names=foo,bar,baz,toto,tutu,tata - -# Colon-delimited sets of names that determine each other's naming style when -# the name regexes allow several styles. -name-group= - -# Include a hint for the correct naming format with invalid-name -include-naming-hint=no - -# Regular expression matching correct function names -function-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for function names -function-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct variable names -variable-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for variable names -variable-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct constant names -const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Naming hint for constant names -const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ - -# Regular expression matching correct attribute names -attr-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for attribute names -attr-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct argument names -argument-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for argument names -argument-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression matching correct class attribute names -class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Naming hint for class attribute names -class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ - -# Regular expression matching correct inline iteration names -inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ - -# Naming hint for inline iteration names -inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ - -# Regular expression matching correct class names -class-rgx=[A-Z_][a-zA-Z0-9]+$ - -# Naming hint for class names -class-name-hint=[A-Z_][a-zA-Z0-9]+$ - -# Regular expression matching correct module names -module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Naming hint for module names -module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ - -# Regular expression matching correct method names -method-rgx=[a-z_][a-z0-9_]{2,30}$ - -# Naming hint for method names -method-name-hint=[a-z_][a-z0-9_]{2,30}$ - -# Regular expression which should only match function or class names that do -# not require a docstring. -no-docstring-rgx=__.*__ - -# Minimum line length for functions/classes that require docstrings, shorter -# ones are exempt. -docstring-min-length=-1 - - -[SPELLING] - -# Spelling dictionary name. Available dictionaries: none. To make it working -# install python-enchant package. -spelling-dict= - -# List of comma separated words that should not be checked. -spelling-ignore-words= - -# A path to a file that contains private dictionary; one word per line. -spelling-private-dict-file= - -# Tells whether to store unknown words to indicated private dictionary in -# --spelling-private-dict-file option instead of raising a message. -spelling-store-unknown-words=no - - -[FORMAT] - -# Maximum number of characters on a single line. -max-line-length=80 - -# Regexp for a line that is allowed to be longer than the limit. -ignore-long-lines=^\s*(# )??$ - -# Allow the body of an if to be on the same line as the test if there is no -# else. -single-line-if-stmt=no - -# List of optional constructs for which whitespace checking is disabled -no-space-check=trailing-comma,dict-separator - -# Maximum number of lines in a module -max-module-lines=1000 - -# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 -# tab). -indent-string=' ' - -# Number of spaces of indent required inside a hanging or continued line. -indent-after-paren=4 - -# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. -expected-line-ending-format=LF - - -[LOGGING] - -# Logging modules to check that the string format arguments are in logging -# function parameter format -logging-modules=logging - - -[VARIABLES] - -# Tells whether we should check for unused import in __init__ files. -init-import=no - -# A regular expression matching the name of dummy variables (i.e. expectedly -# not used). -dummy-variables-rgx=_$|dummy - -# List of additional names supposed to be defined in builtins. Remember that -# you should avoid to define new builtins when possible. -additional-builtins= - -# List of strings which can identify a callback function by name. A callback -# name must start or end with one of those strings. -callbacks=cb_,_cb - - -[DESIGN] - -# Maximum number of arguments for function / method -max-args=5 - -# Argument names that match this expression will be ignored. Default to name -# with leading underscore -ignored-argument-names=_.* - -# Maximum number of locals for function / method body -max-locals=15 - -# Maximum number of return / yield for function / method body -max-returns=6 - -# Maximum number of branch for function / method body -max-branches=12 - -# Maximum number of statements in function / method body -max-statements=50 - -# Maximum number of parents for a class (see R0901). -max-parents=7 - -# Maximum number of attributes for a class (see R0902). -max-attributes=7 - -# Minimum number of public methods for a class (see R0903). -min-public-methods=2 - -# Maximum number of public methods for a class (see R0904). -max-public-methods=20 - - -[IMPORTS] - -# Deprecated modules which should not be used, separated by a comma -deprecated-modules=regsub,TERMIOS,Bastion,rexec - -# Create a graph of every (i.e. internal and external) dependencies in the -# given file (report RP0402 must not be disabled) -import-graph= - -# Create a graph of external dependencies in the given file (report RP0402 must -# not be disabled) -ext-import-graph= - -# Create a graph of internal dependencies in the given file (report RP0402 must -# not be disabled) -int-import-graph= - - -[CLASSES] - -# List of interface methods to ignore, separated by a comma. This is used for -# instance to not check methods defines in Zope's Interface base class. -ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by - -# List of method names used to declare (i.e. assign) instance attributes. -defining-attr-methods=__init__,__new__,setUp - -# List of valid names for the first argument in a class method. -valid-classmethod-first-arg=cls - -# List of valid names for the first argument in a metaclass class method. -valid-metaclass-classmethod-first-arg=mcs - -# List of member names, which should be excluded from the protected access -# warning. -exclude-protected=_asdict,_fields,_replace,_source,_make - - -[EXCEPTIONS] - -# Exceptions that will emit a warning when being caught. Defaults to -# "Exception" -overgeneral-exceptions=Exception diff --git a/releasetools/rangelib.py b/releasetools/rangelib.py deleted file mode 100644 index 1506658..0000000 --- a/releasetools/rangelib.py +++ /dev/null @@ -1,266 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function -import heapq -import itertools - -__all__ = ["RangeSet"] - -class RangeSet(object): - """A RangeSet represents a set of nonoverlapping ranges on the - integers (ie, a set of integers, but efficient when the set contains - lots of runs.""" - - def __init__(self, data=None): - self.monotonic = False - if isinstance(data, str): - self._parse_internal(data) - elif data: - self.data = tuple(self._remove_pairs(data)) - else: - self.data = () - - def __iter__(self): - for i in range(0, len(self.data), 2): - yield self.data[i:i+2] - - def __eq__(self, other): - return self.data == other.data - def __ne__(self, other): - return self.data != other.data - def __nonzero__(self): - return bool(self.data) - - def __str__(self): - if not self.data: - return "empty" - else: - return self.to_string() - - def __repr__(self): - return '' - - @classmethod - def parse(cls, text): - """Parse a text string consisting of a space-separated list of - blocks and ranges, eg "10-20 30 35-40". Ranges are interpreted to - include both their ends (so the above example represents 18 - individual blocks. Returns a RangeSet object. - - If the input has all its blocks in increasing order, then returned - RangeSet will have an extra attribute 'monotonic' that is set to - True. For example the input "10-20 30" is monotonic, but the input - "15-20 30 10-14" is not, even though they represent the same set - of blocks (and the two RangeSets will compare equal with ==). - """ - return cls(text) - - def _parse_internal(self, text): - data = [] - last = -1 - monotonic = True - for p in text.split(): - if "-" in p: - s, e = p.split("-") - data.append(int(s)) - data.append(int(e)+1) - if last <= s <= e: - last = e - else: - monotonic = False - else: - s = int(p) - data.append(s) - data.append(s+1) - if last <= s: - last = s+1 - else: - monotonic = True - data.sort() - self.data = tuple(self._remove_pairs(data)) - self.monotonic = monotonic - - @staticmethod - def _remove_pairs(source): - last = None - for i in source: - if i == last: - last = None - else: - if last is not None: - yield last - last = i - if last is not None: - yield last - - def to_string(self): - out = [] - for i in range(0, len(self.data), 2): - s, e = self.data[i:i+2] - if e == s+1: - out.append(str(s)) - else: - out.append(str(s) + "-" + str(e-1)) - return " ".join(out) - - def to_string_raw(self): - return str(len(self.data)) + "," + ",".join(str(i) for i in self.data) - - def union(self, other): - """Return a new RangeSet representing the union of this RangeSet - with the argument. - - >>> RangeSet("10-19 30-34").union(RangeSet("18-29")) - - >>> RangeSet("10-19 30-34").union(RangeSet("22 32")) - - """ - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 0 and d == 1) or (z == 1 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def intersect(self, other): - """Return a new RangeSet representing the intersection of this - RangeSet with the argument. - - >>> RangeSet("10-19 30-34").intersect(RangeSet("18-32")) - - >>> RangeSet("10-19 30-34").intersect(RangeSet("22-28")) - - """ - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 1 and d == 1) or (z == 2 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def subtract(self, other): - """Return a new RangeSet representing subtracting the argument - from this RangeSet. - - >>> RangeSet("10-19 30-34").subtract(RangeSet("18-32")) - - >>> RangeSet("10-19 30-34").subtract(RangeSet("22-28")) - - """ - - out = [] - z = 0 - for p, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((-1, +1)))): - if (z == 0 and d == 1) or (z == 1 and d == -1): - out.append(p) - z += d - return RangeSet(data=out) - - def overlaps(self, other): - """Returns true if the argument has a nonempty overlap with this - RangeSet. - - >>> RangeSet("10-19 30-34").overlaps(RangeSet("18-32")) - True - >>> RangeSet("10-19 30-34").overlaps(RangeSet("22-28")) - False - """ - - # This is like intersect, but we can stop as soon as we discover the - # output is going to be nonempty. - z = 0 - for _, d in heapq.merge(zip(self.data, itertools.cycle((+1, -1))), - zip(other.data, itertools.cycle((+1, -1)))): - if (z == 1 and d == 1) or (z == 2 and d == -1): - return True - z += d - return False - - def size(self): - """Returns the total size of the RangeSet (ie, how many integers - are in the set). - - >>> RangeSet("10-19 30-34").size() - 15 - """ - - total = 0 - for i, p in enumerate(self.data): - if i % 2: - total += p - else: - total -= p - return total - - def map_within(self, other): - """'other' should be a subset of 'self'. Returns a RangeSet - representing what 'other' would get translated to if the integers - of 'self' were translated down to be contiguous starting at zero. - - >>> RangeSet("0-9").map_within(RangeSet("3-4")) - - >>> RangeSet("10-19").map_within(RangeSet("13-14")) - - >>> RangeSet("10-19 30-39").map_within(RangeSet("17-19 30-32")) - - >>> RangeSet("10-19 30-39").map_within(RangeSet("12-13 17-19 30-32")) - - """ - - out = [] - offset = 0 - start = None - for p, d in heapq.merge(zip(self.data, itertools.cycle((-5, +5))), - zip(other.data, itertools.cycle((-1, +1)))): - if d == -5: - start = p - elif d == +5: - offset += p-start - start = None - else: - out.append(offset + p - start) - return RangeSet(data=out) - - def extend(self, n): - """Extend the RangeSet by 'n' blocks. - - The lower bound is guaranteed to be non-negative. - - >>> RangeSet("0-9").extend(1) - - >>> RangeSet("10-19").extend(15) - - >>> RangeSet("10-19 30-39").extend(4) - - >>> RangeSet("10-19 30-39").extend(10) - - """ - out = self - for i in range(0, len(self.data), 2): - s, e = self.data[i:i+2] - s1 = max(0, s - n) - e1 = e + n - out = out.union(RangeSet(str(s1) + "-" + str(e1-1))) - return out - - -if __name__ == "__main__": - import doctest - doctest.testmod() diff --git a/releasetools/recoverylink.py b/releasetools/recoverylink.py index 5f9fe9d..9c23ae3 100644 --- a/releasetools/recoverylink.py +++ b/releasetools/recoverylink.py @@ -12,11 +12,17 @@ for line in linelist: line = line.rstrip() filepath = line.split('|') - link_name = filepath[0].replace('system', 'SYSTEM') - target = filepath[1] - cmd = 'cd ' + path + ';' + 'mkdir -p ' + os.path.dirname(link_name) + ';' + 'ln -sf ' + target + ' ' + link_name + ';' - print cmd - os.popen(cmd) + filepath[0] = filepath[0].replace('system', 'SYSTEM') + filepath[1] = filepath[1].replace('system', 'SYSTEM') + rm = 'rm -f ' + path+ '/' + filepath[0] + os.popen(rm) + dirname=os.path.dirname(filepath[0]) + filepath[0] = os.path.basename(filepath[0]) + filepath[1] = os.path.basename(filepath[1]) + #ln = 'ln -s '+ path+ '/'+ filepath[1] + ' ' + path+ '/'+ filepath[0] + ln = 'cd ' + path + '/' + dirname + ';' + 'ln -s ' + filepath[1] + ' ' + filepath[0] + #print ln + os.popen(ln) except IOError: print r"%s isn't exist" % linkfile_path sys.exit(1) diff --git a/releasetools/sign_target_files_apks b/releasetools/sign_target_files_apks index ab97b13..fc71b51 100755 --- a/releasetools/sign_target_files_apks +++ b/releasetools/sign_target_files_apks @@ -183,7 +183,7 @@ def RewriteProps(data): for line in data.split("\n"): line = line.strip() original_line = line - if line and line[0] != '#' and "=" in line: + if line and line[0] != '#': key, value = line.split("=", 1) if key == "ro.build.fingerprint": pieces = value.split("/") diff --git a/releasetools/sparse_img.py b/releasetools/sparse_img.py deleted file mode 100644 index 07f3c1c..0000000 --- a/releasetools/sparse_img.py +++ /dev/null @@ -1,247 +0,0 @@ -# Copyright (C) 2014 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import bisect -import os -import struct -from hashlib import sha1 - -import rangelib - - -class SparseImage(object): - """Wraps a sparse image file into an image object. - - Wraps a sparse image file (and optional file map and clobbered_blocks) into - an image object suitable for passing to BlockImageDiff. file_map contains - the mapping between files and their blocks. clobbered_blocks contains the set - of blocks that should be always written to the target regardless of the old - contents (i.e. copying instead of patching). clobbered_blocks should be in - the form of a string like "0" or "0 1-5 8". - """ - - def __init__(self, simg_fn, file_map_fn=None, clobbered_blocks=None): - self.simg_f = f = open(simg_fn, "rb") - - header_bin = f.read(28) - header = struct.unpack("> 2)) - to_read -= this_read - - while to_read > 0: - # continue with following chunks if this range spans multiple chunks. - idx += 1 - chunk_start, chunk_len, filepos, fill_data = self.offset_map[idx] - this_read = min(chunk_len, to_read) - if filepos is not None: - f.seek(filepos, os.SEEK_SET) - yield f.read(this_read * self.blocksize) - else: - yield fill_data * (this_read * (self.blocksize >> 2)) - to_read -= this_read - - def LoadFileBlockMap(self, fn, clobbered_blocks): - remaining = self.care_map - self.file_map = out = {} - - with open(fn) as f: - for line in f: - fn, ranges = line.split(None, 1) - ranges = rangelib.RangeSet.parse(ranges) - out[fn] = ranges - assert ranges.size() == ranges.intersect(remaining).size() - - # Currently we assume that blocks in clobbered_blocks are not part of - # any file. - assert not clobbered_blocks.overlaps(ranges) - remaining = remaining.subtract(ranges) - - remaining = remaining.subtract(clobbered_blocks) - - # For all the remaining blocks in the care_map (ie, those that - # aren't part of the data for any file nor part of the clobbered_blocks), - # divide them into blocks that are all zero and blocks that aren't. - # (Zero blocks are handled specially because (1) there are usually - # a lot of them and (2) bsdiff handles files with long sequences of - # repeated bytes especially poorly.) - - zero_blocks = [] - nonzero_blocks = [] - reference = '\0' * self.blocksize - - f = self.simg_f - for s, e in remaining: - for b in range(s, e): - idx = bisect.bisect_right(self.offset_index, b) - 1 - chunk_start, _, filepos, fill_data = self.offset_map[idx] - if filepos is not None: - filepos += (b-chunk_start) * self.blocksize - f.seek(filepos, os.SEEK_SET) - data = f.read(self.blocksize) - else: - if fill_data == reference[:4]: # fill with all zeros - data = reference - else: - data = None - - if data == reference: - zero_blocks.append(b) - zero_blocks.append(b+1) - else: - nonzero_blocks.append(b) - nonzero_blocks.append(b+1) - - assert zero_blocks or nonzero_blocks or clobbered_blocks - - if zero_blocks: - out["__ZERO"] = rangelib.RangeSet(data=zero_blocks) - if nonzero_blocks: - out["__NONZERO"] = rangelib.RangeSet(data=nonzero_blocks) - if clobbered_blocks: - out["__COPY"] = clobbered_blocks - - def ResetFileMap(self): - """Throw away the file map and treat the entire image as - undifferentiated data.""" - self.file_map = {"__DATA": self.care_map} diff --git a/replace_package_name.sh b/replace_package_name.sh deleted file mode 100755 index 20a68a7..0000000 --- a/replace_package_name.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -if [ $# -ne 3 ] -then - echo $0 path src_package_name dest_package_name - echo - exit -fi - -path="$1" -src="$2" -des="$3" - -cd $path -#replace xml -for f in $(find . -name "*.xml") -do - echo $f - sed "s/$src/$des/g" $f > tmp - mv tmp $f -done - -#replace smali -src2=$(echo $src | sed "s#\.#\\\/#g") -des2=$(echo $des | sed "s#\.#\\\/#g") -for f in $(find . -name "*.smali") -do - echo $f - sed "s/$src2/$des2/g" $f > tmp - mv tmp $f -done - - - diff --git a/resolve_patch.sh b/resolve_patch.sh deleted file mode 100644 index ff7bd66..0000000 --- a/resolve_patch.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -rm -r tmp -rm -r tmp2 -mkdir tmp -mkdir tmp2 - -for f in `grep -rn "access" $1 | cut -d: -f1 | uniq | sort` -do - sed -i "s/access\$.*.(/access\$9999(/g" $f -done - -for f in `grep -rn "access" $2 | cut -d: -f1 | uniq | sort` -do - sed -i "s/access\$.*.(/access\$9999(/g" $f -done - -for ori in `find $1 -name *.smali` -do - filepath=`dirname $ori` - filename=`basename $ori .smali` - if [ -f ${ori/$1/$2} ];then - diff -Naur $ori ${ori/$1/$2} > tmp/"$filename.patch" - if [ $? -eq 0 ] ; then - rm tmp/"$filename.patch" - echo "Processing file:$filename.patch" - else java -jar PatchResolver.jar ${ori/$1/$3} ${ori/$1/$4} tmp/"$filename.patch" > tmp2/"$filename.patch" - fi - fi -done - - - - diff --git a/restore_obsolete_keyguard.sh b/restore_obsolete_keyguard.sh deleted file mode 100755 index 009ac55..0000000 --- a/restore_obsolete_keyguard.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -if [ -d "android.policy.jar.out/smali/com/android/internal/policy/impl/keyguard_obsolete" ];then - -cd android.policy.jar.out/smali/com/android/internal/policy/impl -cp keyguard_obsolete/*.smali . - -rm -r ./keyguard_obsolete -mv ./keyguard ../ - -for smali in `find . -name '*.smali'` -do - sed -i "s/\/keyguard_obsolete\//\//g" $smali - sed -i "s/\/keyguard\//\//g" $smali -done - -mv ../keyguard ./ - -cd - - -fi diff --git a/set_build_prop.sh b/set_build_prop.sh new file mode 100755 index 0000000..0fdc254 --- /dev/null +++ b/set_build_prop.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +build_prop_file=$1 +# other arguments: # product=$2 # number=$3 # version=$4 + +cat $build_prop_file | sed -e "s/ro\.build\.version\.incremental=.*/ro\.build\.version\.incremental=$3/" \ + | sed -e "s/ro\.product\.mod_device=.*//" > $build_prop_file.new + +echo "ro.product.mod_device=$2" >> $build_prop_file.new +echo "ro.skia.use_data_fonts=1" >> $build_prop_file.new +mv $build_prop_file.new $build_prop_file + diff --git a/signapk.jar b/signapk.jar index fbf121f..f6fe372 100644 Binary files a/signapk.jar and b/signapk.jar differ diff --git a/smali b/smali index 9ede675..e8bed94 100755 --- a/smali +++ b/smali @@ -14,12 +14,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# As per the Apache license requirements, this file has been modified -# from its original state. -# -# Such modifications are Copyright (C) 2010 Ben Gruver, and are released -# under the original license - # This script is a wrapper for smali.jar, so you can simply call "smali", # instead of java -jar smali.jar. It is heavily based on the "dx" script # from the Android SDK @@ -61,8 +55,8 @@ javaOpts="" # If you want DX to have more memory when executing, uncomment the following # line and adjust the value accordingly. Use "java -X" for a list of options # you can pass here. -# -javaOpts="-Xmx512M" +# +javaOpts="-Xmx256M" # Alternatively, this will extract any parameter "-Jxxx" from the command line # and pass them to Java (instead of to dx). This makes it possible for you to @@ -75,9 +69,9 @@ while expr "x$1" : 'x-J' >/dev/null; do done if [ "$OSTYPE" = "cygwin" ] ; then - jarpath=`cygpath -w "$libdir/$jarfile"` + jarpath=`cygpath -w "$libdir/$jarfile"` else - jarpath="$libdir/$jarfile" + jarpath="$libdir/$jarfile" fi exec java $javaOpts -jar "$jarpath" "$@" diff --git a/smali.jar b/smali.jar index 36df92e..920a567 100644 Binary files a/smali.jar and b/smali.jar differ diff --git a/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk b/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk new file mode 100644 index 0000000..01a3e10 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/91xiongmaokanshu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/duokanyuedu.apk b/target_files_template/DATA/media/preset_apps/duokanyuedu.apk new file mode 100644 index 0000000..84557e0 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/duokanyuedu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk b/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk new file mode 100644 index 0000000..b016621 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshandianchiyisheng.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk b/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk new file mode 100644 index 0000000..8461f4d Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshankuaipan.apk differ diff --git a/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk b/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk new file mode 100644 index 0000000..266dce1 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/jinshanshoujiweishi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk b/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk new file mode 100644 index 0000000..b96970b Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/kuaijiejiudianguanjia.apk differ diff --git a/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk b/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk new file mode 100644 index 0000000..268dda0 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/kuwoyinyue.apk differ diff --git a/target_files_template/DATA/media/preset_apps/laohuditu.apk b/target_files_template/DATA/media/preset_apps/laohuditu.apk new file mode 100644 index 0000000..1a14c49 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/laohuditu.apk differ diff --git a/target_files_template/DATA/media/preset_apps/meilishuo.apk b/target_files_template/DATA/media/preset_apps/meilishuo.apk new file mode 100644 index 0000000..b34218c Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/meilishuo.apk differ diff --git a/target_files_template/DATA/media/preset_apps/miliao.apk b/target_files_template/DATA/media/preset_apps/miliao.apk new file mode 100644 index 0000000..24c4b53 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/miliao.apk differ diff --git a/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk b/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk new file mode 100644 index 0000000..04fe624 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/oupengliulanqi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/souhuxinwen.apk b/target_files_template/DATA/media/preset_apps/souhuxinwen.apk new file mode 100644 index 0000000..13c47f5 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/souhuxinwen.apk differ diff --git a/target_files_template/DATA/media/preset_apps/ucliulanqi.apk b/target_files_template/DATA/media/preset_apps/ucliulanqi.apk new file mode 100644 index 0000000..5f97aeb Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/ucliulanqi.apk differ diff --git a/target_files_template/DATA/media/preset_apps/vancl.apk b/target_files_template/DATA/media/preset_apps/vancl.apk new file mode 100644 index 0000000..11052cd Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/vancl.apk differ diff --git a/target_files_template/DATA/media/preset_apps/wangyixinwen.apk b/target_files_template/DATA/media/preset_apps/wangyixinwen.apk new file mode 100644 index 0000000..7d9d83c Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/wangyixinwen.apk differ diff --git a/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk b/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk new file mode 100644 index 0000000..7b91e22 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/xiechengwuxian.apk differ diff --git a/target_files_template/DATA/media/preset_apps/xinlangweibo.apk b/target_files_template/DATA/media/preset_apps/xinlangweibo.apk new file mode 100644 index 0000000..66e80c4 Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/xinlangweibo.apk differ diff --git a/target_files_template/DATA/media/preset_apps/youjia.apk b/target_files_template/DATA/media/preset_apps/youjia.apk new file mode 100644 index 0000000..36f539f Binary files /dev/null and b/target_files_template/DATA/media/preset_apps/youjia.apk differ diff --git a/target_files_template/META/apkcerts.txt b/target_files_template/META/apkcerts.txt index e69de29..d53837b 100644 --- a/target_files_template/META/apkcerts.txt +++ b/target_files_template/META/apkcerts.txt @@ -0,0 +1,416 @@ +name="CtsVerifier.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTestStubs.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccelerationTestStubs.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDelegatingAccessibilityService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemosReferenceTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAppAccessData.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsAppWithData.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsInstrumentationAppDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsPermissionDeclareApp.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSharedUidInstall.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSharedUidInstallDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsSimpleAppInstall.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsSimpleAppInstallDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="CtsTargetInstrumentationApp.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey1.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey1.pk8" +name="CtsUsePermissionDiffCert.apk" certificate="cts/tests/appsecurity-tests/certs/cts-testkey2.x509.pem" private_key="cts/tests/appsecurity-tests/certs/cts-testkey2.pk8" +name="android.core.tests.libcore.package.com.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.com.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.dalvik.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.dalvik.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.libcore.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.libcore.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.org.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.org.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.sun.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.sun.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.tests.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.libcore.package.tests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.runner.no-core-tests-res.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="android.core.tests.runner.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDeviceAdmin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ProcessTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoShareUidApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ShareUidApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SignatureTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SignatureTestTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccelerationTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccessibilityServiceTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAccountManagerTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAdminTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsAppTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsBluetoothTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsContentTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDatabaseTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDpiTestCases2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDpiTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsDrmTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsExampleTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsGestureTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsGraphicsTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsHardwareTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsHoloTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsJniTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsLocationTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsMediaTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsNdefTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsNetTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsOsTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPermission2TestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPermissionTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsPreferenceTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsProviderTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsRenderscriptTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSaxTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSecurityTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsSpeechTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTelephonyTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsTextTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsUtilTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsViewTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsWebkitTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CtsWidgetTestCases.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestDeviceSetup.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothDebug.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BuildWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CustomLocale.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Development.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Fallback.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FontLab.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GestureBuilder.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NinePatchLab.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SdkSetup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WidgetPreview.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="launchperf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AccelerometerPlay.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ActionBarCompat.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AliasActivity.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidBeamDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ApiDemosTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BackupRestore.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BasicGLSurfaceView.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothChat.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothHDP.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleBrowserPlugin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BusinessCard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Compass.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ContactManager.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CubeLiveWallpapers.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FixedGridLayout.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GlobalTime.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloActivity.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloActivityTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Home.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HoneycombGallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="JETBoy.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LunarLander.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LunarLanderTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MultiResolution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NFCDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NotePad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ObbApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RSSReader.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RandomMusicPlayer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsBalls.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsFountain.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsFountainFbo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsHelloCompute.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsHelloWorld.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RsMiscSamples.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleSyncAdapter.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SearchableDictionary.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SimpleJNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SipDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SkeletonApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SkeletonAppTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Snake.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SnakeTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SoftKeyboard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HelloSpellChecker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleSpellChecker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="StackWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Support13Demos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Support4Demos.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ToyVpn.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TtsEngine.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AdbTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MissileLauncher.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceRecognitionService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoicemailProviderDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WeatherListWidget.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WiFiDirectDemo.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Wiktionary.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WiktionarySimple.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="xmladapters.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ConnectivityTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GpsLocationTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv1Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv2Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv3.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Notepadv3Solution.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ChromeBookmarksSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="FaceLock.apk" certificate="PRESIGNED" private_key="" +name="Gmail.apk" certificate="PRESIGNED" private_key="" +name="Gmail_Data.apk" certificate="PRESIGNED" private_key="" +name="GoogleBackupTransport.apk" certificate="PRESIGNED" private_key="" +name="GoogleCalendarSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="GoogleContactsSyncAdapter.apk" certificate="PRESIGNED" private_key="" +name="GoogleLoginService.apk" certificate="PRESIGNED" private_key="" +name="GooglePartnerSetup.apk" certificate="PRESIGNED" private_key="" +name="GoogleServicesFramework.apk" certificate="PRESIGNED" private_key="" +name="Maps.apk" certificate="PRESIGNED" private_key="" +name="Maps_Data.apk" certificate="PRESIGNED" private_key="" +name="NetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="Talk.apk" certificate="PRESIGNED" private_key="" +name="Talk_Data.apk" certificate="PRESIGNED" private_key="" +name="Vending.apk" certificate="PRESIGNED" private_key="" +name="VoiceSearch.apk" certificate="PRESIGNED" private_key="" +name="VoiceSearch_Data.apk" certificate="PRESIGNED" private_key="" +name="PlatformLibraryClient.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SampleEmailPolicy.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="UpgradeExample.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Quake.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="PicoTts.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="framework-res.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="ConnectivityManagerTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BandwidthTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BluetoothTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworksCoreTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworkCoreTests_install_decl_perm.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_auto.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_internal.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_sdcard.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_loc_unspecified.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_use_perm_good.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_uses_feature.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_verifier_bad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkCoreTests_install_verifier_good.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DisabledTestApp.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="EnabledTestApp.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AutoLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AutoLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AutoLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadManagerTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocAllPermsTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocPermFLTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsBTTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExternalSharedPermsDiffKeyTestApp.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="ExternalSharedPermsFLTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="InternalLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocVersionedTestApp_v1.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NoLocVersionedTestApp_v2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SimpleTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExternalLocTestApp_v1_ext.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExternalLocTestApp_v2_none.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExtToIntLocTestApp_v1_ext.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="UpdateExtToIntLocTestApp_v2_int.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_Auto.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_External.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_Internal.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VersatileTestApp_None.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NotificationStressTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksCoreSystemPropertiesTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworksGraphicsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="KeyStoreTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CameraBrowser.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MediaDump.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="mediaframeworktest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="scoaudiotest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SoundPoolTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2CameraEye.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2Java.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GL2JNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLDual.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLJNI.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GLPerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LightingTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TestFramerate.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestLatency.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestEGL.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TestViewport.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BackupRestoreConfirmation.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DefaultContainerService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SettingsProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SharedStorageBackup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SystemUI.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SystemUITests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VpnDialogs.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WAPPushManager.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="WAPPushManagerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkPolicyTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksSaxTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksServicesTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TelephonyMockRilTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworksTelephonyTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkTestRunnerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ActivityTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BandwidthEnforcementTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BatteryWaster.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BrowserPowerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BrowserTestPlugin.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CoreTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DataIdleTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DensityTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DumpRenderTree.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DumpRenderTree2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FixVibrateSetting.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="FrameworkPerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GridLayoutTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HugeBackup.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="HwAccelerationTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImfTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImfTestTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LargeAssetTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="LocationTracker.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LotsOfApps.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="lowstoragetest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="RsComputePerf.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FBOTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ImageProcessing.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ModelViewer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="PerfTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ShadersTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="RSTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SmokeTestApp.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SmokeTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SslLoad.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="StatusBarTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TileBenchmark.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TileBenchmarkTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TransformTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AppWidgetHostTest.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AppWidgetProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BackupTest.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FrameworkPermissionTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidCommonTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="framework-miui-res.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="LBESEC_MIUI.apk" certificate="PRESIGNED" private_key="" +name="TelocationProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="TelocationProviderTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CalendarCommonTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MailCommonTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AndroidVCardTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AntiSpam.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Backup.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BasicSmsReceiver.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BasicSmsReceiverTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Bluetooth.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Browser.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BrowserTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="BugReport.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Calculator.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalculatorTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Calendar.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalendarTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Camera.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CameraTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CellBroadcastReceiver.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CellBroadcastReceiverTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CertInstaller.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="CloudService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiCompass.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Contacts.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ContactsTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="DeskClock.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DeskClockTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Email.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="EmailTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Exchange.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ExchangeTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="FileExplorer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Gallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Gallery2.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MiuiGallery.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Gallery2Tests.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="HTMLViewer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="KeyChain.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KeyChainTestsSupport.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KeyChainTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Launcher2.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LauncherRotationStressTest.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="MiuiHome.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Music.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiSystemUI.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiSystemUITests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Mms.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MmsAppTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="MmsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="NetworkAssistant.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MusicFX.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Nfc.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="NfcTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Notes.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PackageInstaller.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Phone.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PhoneAppTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Protips.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Provision.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="QuickSearchBox.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="QuickSearchBoxBenchmarks.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="QuickSearchBoxTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="NaughtySuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="PartialSuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="SlowSuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="SpammySuggestions.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Settings.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SettingsTests.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SoundRecorder.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SpareParts.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="SpeechRecorder.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Stk.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="SuperMarket.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Tag.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ThemeManager.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Torch.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Updater.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VideoEditor.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceDialer.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="VoiceDialerTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="Weather.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="LatinIME.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LatinIMETests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ApplicationsProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ApplicationsProviderTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="CalendarProvider.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CalendarProviderTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="ContactsProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="ContactsProviderTests.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="DownloadProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DownloadProviderTests.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DownloadProviderPermissionTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadPublicApiAccessTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="DownloadProviderUi.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="DrmProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="MediaProvider.apk" certificate="build/target/product/security/media.x509.pem" private_key="build/target/product/security/media.pk8" +name="TelephonyProvider.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="UserDictionaryProvider.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LiveWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="Galaxy4.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="HoloSpiralWallpaper.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="LiveWallpapersPicker.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MagicSmokeWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="VisualizationWallpapers.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="NoiseField.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="PhaseBeam.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="CameraEffectsRecordingSample.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="CameraEffectsTests.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="native-media.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="WeatherProvider.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="GuardProvider.apk" certificate="PRESIGNED" private_key="" +name="XiaomiServiceFramework.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiuiVideoPlayer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="VoiceAssist.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="GameCenter.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="InputMethod.apk" certificate="PRESIGNED" private_key="" +name="AlipayMsp.apk" certificate="PRESIGNED" private_key="" +name="MiuiVideo.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="StockSettings.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="DataHubProvider.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="AirkanPhoneService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" diff --git a/target_files_template/META/filesystem_config.txt b/target_files_template/META/filesystem_config.txt index a17445c..953bd93 100644 --- a/target_files_template/META/filesystem_config.txt +++ b/target_files_template/META/filesystem_config.txt @@ -1,4 +1,5 @@ -system/bin/app_process32_vendor 0 2000 755 selabel=u:object_r:zygote_exec:s0 capabilities=0x0 -system/bin/app_process64_vendor 0 2000 755 selabel=u:object_r:zygote_exec:s0 capabilities=0x0 -system/xbin/shelld 0 2000 755 selabel=u:object_r:system_file:s0 capabilities=0x0 -system/bin/fdpp 0 2000 755 selabel=u:object_r:system_file:s0 capabilities=0x0 +system/xbin/invoke-as 0 0 6755 +system/xbin/su 0 0 6755 +system/xbin/busybox 0 0 6755 +system/xbin/insecure 0 2000 6755 +system/xbin/shelld 0 2000 0755 diff --git a/target_files_template/META/misc_info.txt b/target_files_template/META/misc_info.txt index 446d190..33d303e 100644 --- a/target_files_template/META/misc_info.txt +++ b/target_files_template/META/misc_info.txt @@ -1,4 +1,7 @@ recovery_api_version=3 -fstab_version=1 -use_set_metadata=1 +blocksize=131072 +boot_size=0x00280000 +recovery_size=0x00500000 +system_size=0x08400000 +userdata_size=0x0c440000 tool_extensions=. diff --git a/target_files_template/OTA/bin/busybox b/target_files_template/OTA/bin/busybox deleted file mode 100644 index 9539dea..0000000 Binary files a/target_files_template/OTA/bin/busybox and /dev/null differ diff --git a/target_files_template/OTA/bin/relink b/target_files_template/OTA/bin/relink deleted file mode 100644 index 98615ac..0000000 Binary files a/target_files_template/OTA/bin/relink and /dev/null differ diff --git a/target_files_template/OTA/bin/replace_key b/target_files_template/OTA/bin/replace_key deleted file mode 100644 index 300a598..0000000 --- a/target_files_template/OTA/bin/replace_key +++ /dev/null @@ -1,22 +0,0 @@ -debug_platform="308204a830820390a003020102020900b3998086d056cffa300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353232343035305a170d3335303930313232343035305a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d003082010802820101009c780592ac0d5d381cdeaa65ecc8a6006e36480c6d7207b12011be50863aabe2b55d009adf7146d6f2202280c7cd4d7bdb26243b8a806c26b34b137523a49268224904dc01493e7c0acf1a05c874f69b037b60309d9074d24280e16bad2a8734361951eaf72a482d09b204b1875e12ac98c1aa773d6800b9eafde56d58bed8e8da16f9a360099c37a834a6dfedb7b6b44a049e07a269fccf2c5496f2cf36d64df90a3b8d8f34a3baab4cf53371ab27719b3ba58754ad0c53fc14e1db45d51e234fbbe93c9ba4edf9ce54261350ec535607bf69a2ff4aa07db5f7ea200d09a6c1b49e21402f89ed1190893aab5a9180f152e82f85a45753cf5fc19071c5eec827020103a381fc3081f9301d0603551d0e041604144fe4a0b3dd9cba29f71d7287c4e7c38f2086c2993081c90603551d230481c13081be80144fe4a0b3dd9cba29f71d7287c4e7c38f2086c299a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900b3998086d056cffa300c0603551d13040530030101ff300d06092a864886f70d01010405000382010100572551b8d93a1f73de0f6d469f86dad6701400293c88a0cd7cd778b73dafcc197fab76e6212e56c1c761cfc42fd733de52c50ae08814cefc0a3b5a1a4346054d829f1d82b42b2048bf88b5d14929ef85f60edd12d72d55657e22e3e85d04c831d613d19938bb8982247fa321256ba12d1d6a8f92ea1db1c373317ba0c037f0d1aff645aef224979fba6e7a14bc025c71b98138cef3ddfc059617cf24845cf7b40d6382f7275ed738495ab6e5931b9421765c491b72fb68e080dbdb58c2029d347c8b328ce43ef6a8b15533edfbe989bd6a48dd4b202eda94c6ab8dd5b8399203daae2ed446232e4fe9bd961394c6300e5138e3cfd285e6e4e483538cb8b1b357" -debug_shared="308204a830820390a003020102020900b3998086d056cffa300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353232343035305a170d3335303930313232343035305a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d003082010802820101009c780592ac0d5d381cdeaa65ecc8a6006e36480c6d7207b12011be50863aabe2b55d009adf7146d6f2202280c7cd4d7bdb26243b8a806c26b34b137523a49268224904dc01493e7c0acf1a05c874f69b037b60309d9074d24280e16bad2a8734361951eaf72a482d09b204b1875e12ac98c1aa773d6800b9eafde56d58bed8e8da16f9a360099c37a834a6dfedb7b6b44a049e07a269fccf2c5496f2cf36d64df90a3b8d8f34a3baab4cf53371ab27719b3ba58754ad0c53fc14e1db45d51e234fbbe93c9ba4edf9ce54261350ec535607bf69a2ff4aa07db5f7ea200d09a6c1b49e21402f89ed1190893aab5a9180f152e82f85a45753cf5fc19071c5eec827020103a381fc3081f9301d0603551d0e041604144fe4a0b3dd9cba29f71d7287c4e7c38f2086c2993081c90603551d230481c13081be80144fe4a0b3dd9cba29f71d7287c4e7c38f2086c299a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900b3998086d056cffa300c0603551d13040530030101ff300d06092a864886f70d01010405000382010100572551b8d93a1f73de0f6d469f86dad6701400293c88a0cd7cd778b73dafcc197fab76e6212e56c1c761cfc42fd733de52c50ae08814cefc0a3b5a1a4346054d829f1d82b42b2048bf88b5d14929ef85f60edd12d72d55657e22e3e85d04c831d613d19938bb8982247fa321256ba12d1d6a8f92ea1db1c373317ba0c037f0d1aff645aef224979fba6e7a14bc025c71b98138cef3ddfc059617cf24845cf7b40d6382f7275ed738495ab6e5931b9421765c491b72fb68e080dbdb58c2029d347c8b328ce43ef6a8b15533edfbe989bd6a48dd4b202eda94c6ab8dd5b8399203daae2ed446232e4fe9bd961394c6300e5138e3cfd285e6e4e483538cb8b1b357" -debug_media="308204a830820390a003020102020900f2b98e6123572c4e300d06092a864886f70d0101040500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303431353233343035375a170d3335303930313233343035375a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d00308201080282010100ae250c5a16ef97fc2869ac651b3217cc36ba0e86964168d58a049f40ce85867123a3ffb4f6d949c33cf2da3a05c23eacaa57d803889b1759bcf59e7c6f21890ae25085b7ed56aa626c0989ef9ccd36362ca0e8d1b9603fd4d8328767926ccc090c68b775ae7ff30934cc369ef2855a2667df0c667fd0c7cf5d8eba655806737303bb624726eabaedfb72f07ed7a76ab3cb9a381c4b7dcd809b140d891f00213be401f58d6a06a61eadc3a9c2f1c6567285b09ae09342a66fa421eaf93adf7573a028c331d70601ab3af7cc84033ece7c772a3a5b86b0dbe9d777c3a48aa9801edcee2781589f44d9e4113979600576a99410ba81091259dad98c6c68ff784b8f020103a381fc3081f9301d0603551d0e04160414ca293caa8bc0ed3e542eef4205a2bff2b57e4d753081c90603551d230481c13081be8014ca293caa8bc0ed3e542eef4205a2bff2b57e4d75a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900f2b98e6123572c4e300c0603551d13040530030101ff300d06092a864886f70d0101040500038201010084de9516d5e4a87217a73da8487048f53373a5f733f390d61bdf3cc9e5251625bfcaa7c3159cae275d172a9ae1e876d5458127ac542f68290dd510c0029d8f51e0ee156b7b7b5acdb394241b8ec78b74e5c42c5cafae156caf5bd199a23a27524da072debbe378464a533630b0e4d0ffb7e08ecb701fadb6379c74467f6e00c6ed888595380792038756007872c8e3007af423a57a2cab3a282869b64c4b7bd5fc187d0a7e2415965d5aae4e07a6df751b4a75e9793c918a612b81cd0b628aee0168dc44e47b10d3593260849d6adf6d727dc24444c221d3f9ecc368cad07999f2b8105bc1f20d38d41066cc1411c257a96ea4349f5746565507e4e8020a1a81" -debug_testkey="308204a830820390a003020102020900936eacbe07f201df300d06092a864886f70d0101050500308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d301e170d3038303232393031333334365a170d3335303731373031333334365a308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d30820120300d06092a864886f70d01010105000382010d00308201080282010100d6931904dec60b24b1edc762e0d9d8253e3ecd6ceb1de2ff068ca8e8bca8cd6bd3786ea70aa76ce60ebb0f993559ffd93e77a943e7e83d4b64b8e4fea2d3e656f1e267a81bbfb230b578c20443be4c7218b846f5211586f038a14e89c2be387f8ebecf8fcac3da1ee330c9ea93d0a7c3dc4af350220d50080732e0809717ee6a053359e6a694ec2cb3f284a0a466c87a94d83b31093a67372e2f6412c06e6d42f15818dffe0381cc0cd444da6cddc3b82458194801b32564134fbfde98c9287748dbf5676a540d8154c8bbca07b9e247553311c46b9af76fdeeccc8e69e7c8a2d08e782620943f99727d3c04fe72991d99df9bae38a0b2177fa31d5b6afee91f020103a381fc3081f9301d0603551d0e04160414485900563d272c46ae118605a47419ac09ca8c113081c90603551d230481c13081be8014485900563d272c46ae118605a47419ac09ca8c11a1819aa48197308194310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630140603550407130d4d6f756e7461696e20566965773110300e060355040a1307416e64726f69643110300e060355040b1307416e64726f69643110300e06035504031307416e64726f69643122302006092a864886f70d0109011613616e64726f696440616e64726f69642e636f6d820900936eacbe07f201df300c0603551d13040530030101ff300d06092a864886f70d010105050003820101007aaf968ceb50c441055118d0daabaf015b8a765a27a715a2c2b44f221415ffdace03095abfa42df70708726c2069e5c36eddae0400be29452c084bc27eb6a17eac9dbe182c204eb15311f455d824b656dbe4dc2240912d7586fe88951d01a8feb5ae5a4260535df83431052422468c36e22c2a5ef994d61dd7306ae4c9f6951ba3c12f1d1914ddc61f1a62da2df827f603fea5603b2c540dbd7c019c36bab29a4271c117df523cdbc5f3817a49e0efa60cbd7f74177e7a4f193d43f4220772666e4c4d83e1bd5a86087cf34f2dec21e245ca6c2bb016e683638050d2c430eea7c26a1c49d3760a58ab7f1a82cc938b4831384324bd0401fa12163a50570e684d" -patchrom_platform="308203e5308202cda003020102020900b8efb85271e7e740300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303232365a170d3433303630373039303232365a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100b85b306dc881873256284ea4c77a0b3b55f718afe3de21af829697ca4d348641b55ffb80abf13656c88c16606f0f439ae3d1edd62154bd58b17120b0a184493f9c1170003041f4b2b3e9bb61257f7de1499e8c35a606a81c70c305bd8ea325e4572871ec44e62666b30afb5ffc24148e4194e65478547cd13787284f83da5c6b50bd2223adc8b57e786fb1e49e52eba6a06bfa1c6b44b289a8d6d06906e22eb8a527fc123e1faf387548a026e785dbec5bd2dc207f3b2eef18b5a499f245cec19fa8623556caf1d5e41d5c3274d5413c2b1d4cf15eff297fc36894e80344769f6022afe5bf920f271091e438d98425e3953bedf9967ead1d0646e3967b65ed770203010001a350304e301d0603551d0e04160414a1e9aed0be13a7be6d1299f0f4b9993e53d30d8f301f0603551d23041830168014a1e9aed0be13a7be6d1299f0f4b9993e53d30d8f300c0603551d13040530030101ff300d06092a864886f70d010105050003820101009f3e79672817e5aa5202b5e6120b0f952c51dcc1d8b887271dc326e1ebc7cc33c13eab7f284e009ceea5345af916f4c9d2b7a12ef9eb46ee5c799c82664d744256656ad28815d90676b7d01fcbc1eddaf1dfc8d71472a73dc8ecaf630ccdf91a0ff4e624f8892443a2199ad85b0b037163416dd2207ba499efdb7c95193ed17dbef5875fb7ecfe45359ea57007724b0597d7aaf1e458d1f93a21ca10bd145f73c99e7d1208a5aab091b1f16446e329bd12440509711f2a58f40221dffa10a043a85481667516362931b00b1822851678323fef4596c83cc8f332fa3ff736ceb6b10cb1499a28cefb0c3a19157356adaabef7bd953caca1a7b402a8816951ed78" -patchrom_shared="308203e5308202cda003020102020900f716cbd07088bb40300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303235375a170d3433303630373039303235375a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100e293b3780f0da7a69fedd06f9922436b1f0fb4605d4287a0f62826d2db767febc4438cafb1addfe888f57cf9720f1fdf5bf9b8f342de1fbc31c8617aaa23c2b50fdb8d95b292798e8dee84a46a304224a9b80735f2abb966dc5b73c7e34693d00a0b9931aa87595ae35582c4d0ad6dd2eefc1372dd4cc776de7fb046e0c6af7867cb9366c73f8fbce9d7b186384e7b3c299217181677b0bc16d69cea6ac26bc5e8424faa4d3caa89e3fa31c822095e45a08697fcb13054c7f17de86e72b09e0e7be627c25a105b327bb0614eecfe37dcfd0b906930c4ab84eb051f430f493a43158bbf7bc0b474e0409378076cc8ea475b76e5f7ea2cb03194aa7184f5f3ce3b0203010001a350304e301d0603551d0e04160414b449dd6f51e3b354619a47dda7c897323ed723c0301f0603551d23041830168014b449dd6f51e3b354619a47dda7c897323ed723c0300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100b2091ff1a0c23b0027d62101918225fad31d9d37e6bfcc126574324a23611a69f2450db2cc10fbdfd96448386d122a6f8b1b6685a9aa538abcbc659958d9038c5d53c2657bac65d951374716648eee9feab23e85c04bae366d9b8027d283f0e6389b03674a0e98a1859d8e2868be49ad199662c6fe0a98f43232c494622e70b74be77f077833464647d909ae5657b63ec58dbd5d91b6fe2be3981a58a6c8f24d04605a0fcbc86f4a298d9f32bef72fb8123f1a323ee3cd95601863ad07fd6e3ba52da120169eadff6b80ca653d730b94a58ae051682b7c9a8a6c06bd0efdd4a9f5d0320fa08419a749b20c66092bc5ee63864850435b381aac789e6be081cd49" -patchrom_media="308203e5308202cda003020102020900b87815ea377b5c04300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303334325a170d3433303630373039303334325a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a02820101009874294fb2f7fcc01605bc4183a001e0f2fc88b130b3b9531ef3a57ddece1628d26b999ba68969c4c575f56105bcfcc62fca5b6183b8fddc93258cb760edca1b71c4c04f492c985e653195bb0f8791304a82989b379d737cb9aaa14d602fe2bde3df68c909175e99673fbb1ecc2a53adf799f620fcd491ec92b42c779ca5460fca443ea777035ee0771c60945fe0ea2fb88be9b60f3e194053c4366887c9609b7891f3019aaa80129f933c3843013292b84d28041fef05852238a860fa33c955c83f139f646c864d7ddda0c57f6d7aa3f03163f401151a2b982b5c895e5fe1aeef47078b4269255070b600a28f4ac0ec8598e04525aa6939ee62459256ec91b90203010001a350304e301d0603551d0e04160414f6807b81a390e6098014f1722fa0aff1fae60240301f0603551d23041830168014f6807b81a390e6098014f1722fa0aff1fae60240300c0603551d13040530030101ff300d06092a864886f70d01010505000382010100658261e32cfe877b2821423285f404f4eeaecf81a3b0b7fb5d3e7b47e0b5ab79d96fc4a032ebb95dba82a04baa96c9780f81328033e405e72040c69733d47bf1bd5e27e07be3deb8fd94595dda580dbe6251a7dcc8e850f9ec85f64b884f0be0f0aac6e029c4f5d1ed857aa42ddbb7792d76b391dc451c8fe881e6dbbfd61c6482e8c1039b32c3afe03eb1fb213f1e629e329d568392e177c0c1dfd80a4171adfdeb346b9dcd1fbd2b24bf4925ac74c53367bf091772b861c4b90b108b759b2192cec83354a8f092bcdfc52b3051abaebc6cda7b1dd0c8f2c21493742dac4d4497b7ecbb2a83882fea9b6f23ce871f4df49f5cde7bd8480cd7a8a4ab8ba503c6" -patchrom_testkey="308203e5308202cda003020102020900eaf7ddf89372f4d4300d06092a864886f70d0101050500308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d301e170d3136303132303039303331385a170d3433303630373039303331385a308188310b300906035504061302434e3110300e06035504080c074265696a696e673110300e06035504070c074265696a696e67310f300d060355040a0c065869616f6d69310d300b060355040b0c044d4955493111300f06035504030c085061746368526f6d3122302006092a864886f70d01090116137061746368726f6d407869616f6d692e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100bc35fd9be394cdf0872674ce64a5377fe00739ab9a0719d8371aef6ab10e3efd871d735f0aee09eb4f64f50711f2b974ba7b47b61357782786e6a0ae73e26e965ba2032e73caadad5d21b47f0680b742d78c6526a5de33a6100ce0cc3ad6900115d654294f0c8b5a2f810883c7ece88e41eff55a8b0afbf7710bdf86d450fc433aaf46d38f6e1a97bf52a67857ade83b9047e9db23bdf13ceb98d093597d46cc4e495b1a0e2c07dd2e68f79ddbc0aa68f7c949a845ffef02971560cb50781f615f186e653ef39b8fe77ca85ddaeb7c61875830803d474604cf758049d3c47b68bc2aae91fd39ee9e546fb9afe6b5ac0811f80e9bb4f44f106504dc3fca0983910203010001a350304e301d0603551d0e04160414b8c84855c24ae06e1be97879f727f473db2e7b0c301f0603551d23041830168014b8c84855c24ae06e1be97879f727f473db2e7b0c300c0603551d13040530030101ff300d06092a864886f70d0101050500038201010020f9b9414f0fbfcbf3ab84bd327cb14d5f17fce0f4718cb78a5b2ded7f8b1b05dca9b59227deb342736995b1cfb51d19e602466f84d652b2614491485a8677e87283db3c315dae9784868862ec52c08eaa4860b6d1bf53f9e0d6c718f55580404923c7e30fbed93d98bacd53eb1fd05d69116e98cee4ee42f8eca3bad566c06b04a764a799f513531ae594ca7daf3f7c30a93ad859ce9f8b7ed97ab5575b322480215d2f7bcad419a1b742a042708bfba2c912072e9f1f9e0044a1405b4abc4c25291f660340d2cf30f37f06ddbc37345a8937093df9d75b81aa76f618791f162966721dc7830964b443cefaa8448ddba84199053710b2c99b8b8dcf7d965c42" -user_platform="@user_platform" -user_shared="@user_shared" -user_media="@user_media" -user_testkey="@user_testkey" - -/tmp/busybox sed -i "s/$debug_platform/$user_platform/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_shared/$user_shared/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_media/$user_media/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$debug_testkey/$user_testkey/g" /data/system/packages.xml - -/tmp/busybox sed -i "s/$patchrom_platform/$user_platform/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_shared/$user_shared/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_media/$user_media/g" /data/system/packages.xml -/tmp/busybox sed -i "s/$patchrom_testkey/$user_testkey/g" /data/system/packages.xml diff --git a/target_files_template/OTA/bin/updater b/target_files_template/OTA/bin/updater index fe34944..29fbc64 100644 Binary files a/target_files_template/OTA/bin/updater and b/target_files_template/OTA/bin/updater differ diff --git a/uniq_first.py b/uniq_first.py index 11b6896..bbb3404 100755 --- a/uniq_first.py +++ b/uniq_first.py @@ -11,16 +11,30 @@ def uniq_first(src_file, dst_file): with open(dst_file, 'a') as df: for line in lines: - if not (line.split()[0] + " " in content): + if not (line.split()[0] in content): df.write(line) +def filter_miui(miui_file, filter_file, make_dir): + lines = [] + miui_apps = os.popen("make -C "+ make_dir + " miui-apps-included").read() + with open(miui_file, 'r') as mf: + lines = mf.readlines() + + with open(filter_file, 'w') as ff: + for line in lines: + if line.split(): + if (line.split()[0].split('"')[1] in miui_apps): + ff.write(line) + def main(args): - if len(args) != 2: - print("Usage: uniq_first src_file dst_file") + if len(args) != 3: + print("Usage: uniq_first src_file dst_file make_dir") sys.exit(1) - uniq_first(args[0], args[1]) - + filtered = args[1] + '.filter' + filter_miui(args[1], filtered, args[2]) + uniq_first(args[0], filtered) + os.rename(filtered, args[1]) if __name__ == '__main__': main(sys.argv[1:]) diff --git a/unpackbootimg b/unpackbootimg new file mode 100755 index 0000000..067cd63 Binary files /dev/null and b/unpackbootimg differ