diff --git a/ResValuesModify/jar/ResValuesModify b/ResValuesModify/jar/ResValuesModify new file mode 100755 index 0000000..ec75720 --- /dev/null +++ b/ResValuesModify/jar/ResValuesModify @@ -0,0 +1,5 @@ +#!/bin/bash + +java -jar $PORT_ROOT/tools/ResValuesModify/jar/ResValuesModify.jar $* + + diff --git a/ResValuesModify/jar/ResValuesModify.jar b/ResValuesModify/jar/ResValuesModify.jar new file mode 100644 index 0000000..c9dd1b2 Binary files /dev/null and b/ResValuesModify/jar/ResValuesModify.jar differ diff --git a/ResValuesModify/jar/config b/ResValuesModify/jar/config new file mode 100644 index 0000000..0fb4585 --- /dev/null +++ b/ResValuesModify/jar/config @@ -0,0 +1,18 @@ +# 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/Log.java b/ResValuesModify/src/Log.java new file mode 100644 index 0000000..052f58a --- /dev/null +++ b/ResValuesModify/src/Log.java @@ -0,0 +1,21 @@ +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 new file mode 100644 index 0000000..f1f7971 --- /dev/null +++ b/ResValuesModify/src/ResValuesModify.java @@ -0,0 +1,79 @@ +import java.io.File; +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"; + + public static void main(String[] args) { + ResValuesModify resVM = new ResValuesModify(); + if (!resVM.checkArgs(args) || !resVM.checkPath(args)) { + resVM.usage(); + return; + } + resVM.mergeXML(); + } + + private boolean checkArgs(String[] args) { + boolean ret = true; + if (args.length < 2) { + Log.e(LOG_TAG, "invalid argument count"); + return false; + } + + if (args[0].equals(args[1])) { + Log.e(LOG_TAG, "src dir is the same with dest dir"); + ret = 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()); + } + } + return ret; + } + + private boolean checkPath(String[] args) { + return perpareXmlFiles(args[0], mSrcFiles) && perpareXmlFiles(args[1], mDestFiles); + } + + private void mergeXML() { + (new XMLMerge(mSrcFiles, mDestFiles, mConfigFiles)).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; + } +} diff --git a/ResValuesModify/src/XMLMerge.java b/ResValuesModify/src/XMLMerge.java new file mode 100644 index 0000000..5d5dae9 --- /dev/null +++ b/ResValuesModify/src/XMLMerge.java @@ -0,0 +1,446 @@ +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.DocumentBuilderFactory; + +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; + +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"); + } + } + + 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"); + } + } + + 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 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); + } + } + Log.i(""); + Log.i("------------------------------------------------"); + } + + 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()); + } + } + + 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()); + } + } + + 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; + } + + 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(""); + } + + saveDestFile(); + } + + private void saveDestFile() { + for (Map.Entry des : sDes.entrySet()) { + writeXML(des.getValue(), des.getKey()); + } + } + + 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; + } + + private int mergeNode(Node node) { + if (!checkNode(node)) { + Log.i(LOG_TAG, "invalid src node: " + node.getNodeName()); + return MERGE_INVALID_NODE; + } + + if (!needMerge(node)) { + Log.i(LOG_TAG, "dont need merge src node: " + node.getNodeName() + "[" + "name=" + + ((Element) node).getAttribute(NAME_TAG) + "]"); + 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; + } + + 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)); + } + + 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); + } + + 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()); + } + + 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)); + } + } + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return false; + } + } + } + } + return false; + } + + // 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; + } + } + } + return false; + } + + // 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; + } + } + } + return false; + } + + private boolean existNode(Document doc, String nodeName) { + NodeList nodes = doc.getElementsByTagName(nodeName); + return nodes.getLength() > 0; + } + + 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); + } + } + } + } + + 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 void removeXliffgNode(Document doc) { + removeXliffgNodeFromStringArray(doc); + removeXliffgNodeFromString(doc); + } + + 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 void writeXML(Document doc, File file) { + try { + OutputFormat format = new OutputFormat(doc); + format.setIndenting(true); + format.setIndent(4); + Writer output = new BufferedWriter(new FileWriter(file)); + XMLSerializer serializer = new XMLSerializer(output, format); + serializer.serialize(doc); + } catch (Exception e) { + e.printStackTrace(); + Log.e(LOG_TAG, "write xml file " + file.getName() + " failed"); + } + } +} diff --git a/ResValuesModify/src/make_jar b/ResValuesModify/src/make_jar new file mode 100755 index 0000000..e514052 --- /dev/null +++ b/ResValuesModify/src/make_jar @@ -0,0 +1,8 @@ +#!/bin/bash +javac ResValuesModify.java +jar -cvmf manifest.txt ResValuesModify.jar *.class +find -name "*.class" | xargs rm +mkdir -p ../jar +cp ResValuesModify.jar ../jar/ResValuesModify.jar +rm ResValuesModify.jar + diff --git a/ResValuesModify/src/manifest.txt b/ResValuesModify/src/manifest.txt new file mode 100644 index 0000000..8a7b8af --- /dev/null +++ b/ResValuesModify/src/manifest.txt @@ -0,0 +1,2 @@ +Main-Class: ResValuesModify + diff --git a/aapt b/aapt new file mode 100755 index 0000000..b627e59 Binary files /dev/null and b/aapt differ diff --git a/aapt.exe b/aapt.exe new file mode 100755 index 0000000..1f51b87 Binary files /dev/null and b/aapt.exe differ diff --git a/add_miui_res.sh b/add_miui_res.sh new file mode 100755 index 0000000..c864d23 --- /dev/null +++ b/add_miui_res.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# $1: dir for miui overlay framework-res +# $2: dir for target framework-res +# +if [ -f "customize_framework-res.sh" ]; then + ./customize_framework-res.sh $1 $2 +fi diff --git a/add_miui_smail.sh b/add_miui_smail.sh new file mode 100755 index 0000000..9b2e751 --- /dev/null +++ b/add_miui_smail.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# +# $1: dir for miui +# $2: dir for original +# +for file in `find $1 -name "*.smali"` +do + 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 + ./customize_framework.sh $1 $2 +fi diff --git a/apkcerts.py b/apkcerts.py new file mode 100755 index 0000000..3f72c72 --- /dev/null +++ b/apkcerts.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +import sys +import string +import xml +import xml.dom +from xml.dom import minidom + +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" + +def main(): + if len(sys.argv) != 3: + usage() + sys.exit(1) + + try: + xmldoc = minidom.parse(sys.argv[1]) + except : + print "Error: %s doesn't exist or isn't a vaild xml file" %(sys.argv[1]) + sys.exit(1) + + packages = xmldoc.getElementsByTagName("package") + sigpkgs = {} + for pkg in packages: + name = getName(pkg.attributes["codePath"].value) + cert= pkg.getElementsByTagName("cert") + if not cert or not name: continue + index = cert[0].getAttribute("index") + sigpkgs[index] = sigpkgs.get(index, []) + [name] + + sharedUsers = xmldoc.getElementsByTagName("shared-user") + sigmap = {} + for user in sharedUsers: + name = user.getAttribute("name") + cert = user.getElementsByTagName("cert") + if not cert: continue + index = cert[0].getAttribute("index") + if name == "android.uid.system": + sigmap[index] = "platform" + elif name == "android.media": + sigmap[index] = "media" + elif name == "android.uid.shared": + sigmap[index] = "shared" + + with open(sys.argv[2], "w") as f: + for keyindex, pkgnames in sigpkgs.items(): + sig = sigmap.get(keyindex, None) + for pkgname in pkgnames: + if 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}" certificate="PRESIGNED" private_key=""\n'.format(pkgname) + f.write(line) + +if "__main__" == __name__: + main() diff --git a/apktool b/apktool new file mode 100755 index 0000000..b439eff --- /dev/null +++ b/apktool @@ -0,0 +1,77 @@ +#!/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. + +# 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 + +# 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=apktool.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="-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 +# 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/apktool.jar b/apktool.jar new file mode 100644 index 0000000..3d5fc2a Binary files /dev/null and b/apktool.jar differ diff --git a/baksmali b/baksmali new file mode 100755 index 0000000..31f782f --- /dev/null +++ b/baksmali @@ -0,0 +1,77 @@ +#!/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. + +# 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 + +# 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=baksmali.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="-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 +# 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/baksmali.jar b/baksmali.jar new file mode 100644 index 0000000..cc5208b Binary files /dev/null and b/baksmali.jar differ diff --git a/build_libra.sh b/build_libra.sh new file mode 100755 index 0000000..8622f46 --- /dev/null +++ b/build_libra.sh @@ -0,0 +1,9 @@ +#!/bin/bash +if [ -z $2 ] +then + exit 1 +fi + +echo build $2 under $1 +cd $1 +make $2 diff --git a/build_target_files.sh b/build_target_files.sh new file mode 100755 index 0000000..eed0c6e --- /dev/null +++ b/build_target_files.sh @@ -0,0 +1,123 @@ +PRJ_DIR=`pwd` +METADATA_DIR=$PRJ_DIR/metadata +OUT_DIR=$PRJ_DIR/out +ZIP_DIR=$OUT_DIR/ZIP +TARGET_FILES_DIR=$OUT_DIR/target_files +TARGET_FILES_ZIP=$OUT_DIR/target_files.zip +TARGET_FILES_TEMPLATE_DIR=$PORT_ROOT/tools/target_files_template +TOOL_DIR=$PORT_ROOT/tools +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 + +# copy the whole target_files_template dir +function copy_target_files_template { + echo "Copy target file template into current working directory" + rm -rf $TARGET_FILES_DIR + mkdir -p $TARGET_FILES_DIR + cp -r $TARGET_FILES_TEMPLATE_DIR/* $TARGET_FILES_DIR +} + +function copy_bootimage { + echo "Copy bootimage" + for file in boot.img zImage */boot.img */zImage + do + if [ -f $ZIP_DIR/$file ] + then + cp $ZIP_DIR/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/boot.img + return + fi + done +} + +function copy_system_dir { + echo "Copy system dir" + cp -rf $ZIP_DIR/system/* $TARGET_FILES_DIR/SYSTEM +} + +function copy_data_dir { + #The thirdpart apps have copyed in copy_target_files_template function, + #here, just to decide whether delete them. + if [ $INCLUDE_THIRDPART_APP = "true" ];then + echo "Copy thirdpart apps" + else + rm -rf $TARGET_FILES_DIR/DATA/* + fi + echo "Copy miui preinstall apps" + mkdir -p $TARGET_FILES_DIR/DATA/ + cp -rf $ZIP_DIR/data/miui $TARGET_FILES_DIR/DATA/ + if [ -f customize_data.sh ];then + ./customize_data.sh $PRJ_DIR + fi +} + +function recover_link { + cp -f $METADATA_DIR/linkinfo.txt $TARGET_FILES_DIR/SYSTEM + python $TOOL_DIR/releasetools/recoverylink.py $TARGET_FILES_DIR + rm $TARGET_FILES_DIR/SYSTEM/linkinfo.txt +} + +function process_metadata { + echo "Process metadata" + 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 + 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 +} + +# compress the target_files dir into a zip file +function zip_target_files { + echo "Compress the target_files dir into zip file" + echo $TARGET_FILES_DIR + cd $TARGET_FILES_DIR + echo "zip -q -r -y $TARGET_FILES_ZIP *" + zip -q -r -y $TARGET_FILES_ZIP * + cd - +} + +function sign_target_files { + echo "Sign target files" + $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 $PORT_ROOT/build/security/testkey $TARGET_FILES_ZIP $OUT_DIR/$OUT_ZIP_FILE +} + + +if [ $# -eq 3 ];then + NO_SIGN=true + OUT_ZIP_FILE=$3 + INCLUDE_THIRDPART_APP=$1 +elif [ $# -eq 2 ];then + OUT_ZIP_FILE=$2 + INCLUDE_THIRDPART_APP=$1 +elif [ $# -eq 1 ];then + INCLUDE_THIRDPART_APP=$1 +fi + +copy_target_files_template +copy_bootimage +copy_system_dir +copy_data_dir +process_metadata +if [ -f "customize_target_files.sh" ]; then + ./customize_target_files.sh + if [ $? -ne 0 ];then + exit 1 + fi +fi +zip_target_files +if [ -n "$OUT_ZIP_FILE" ];then + if [ "$NO_SIGN" == "false" ];then + sign_target_files + fi + build_ota_package +fi diff --git a/change_rom.sh b/change_rom.sh new file mode 100755 index 0000000..d76d00c --- /dev/null +++ b/change_rom.sh @@ -0,0 +1,116 @@ +#!/bin/bash + +# $1: the old smali code $2: the new smali code $3: the destination smali code + +if [ $# -ne 5 ];then + echo "Usage: change_rom.sh APP|JAR APP_NAME SUFFIX old_rom.zip new_rom.zip" + exit +fi + +# todo run me under product dir, such as i9100 +WS_DIR=`pwd` +APKTOOL=$PORT_ROOT/tools/apktool + +# such as app/Phone (no .apk here) +APPFRM=$1 +appname=$4 +suffix=$5 +app=$APPFRM/$appname.$suffix + +temp_dir=$WS_DIR/temp +old_smali_dir=$WS_DIR/temp_old +dst_smali_dir=$WS_DIR/temp_dst +new_smali_dir=$WS_DIR + +echo ">>> Extract $app from ROM_ZIP file..." +unzip $2 system/$app -d $old_smali_dir +$APKTOOL d $old_smali_dir/system/$app $old_smali_dir/$appname +unzip $3 system/$app -d $dst_smali_dir +$APKTOOL d $dst_smali_dir/system/$app $dst_smali_dir/$appname +echo "<<< Done!" + +temp_old_smali_dir=$temp_dir/old_smali +temp_new_smali_dir=$temp_dir/new_smali +temp_dst_smali_orig_dir=$temp_dir/dst_smali_orig +temp_dst_smali_patched_dir=$temp_dir/dst_smali_patched +reject_dir=$temp_dir/reject + +rm -rf $temp_dir + +echo ">>> create temp directory to store the old, new source and destination smali code with .line removed" +mkdir -p $temp_old_smali_dir +mkdir -p $temp_new_smali_dir +mkdir -p $temp_dst_smali_orig_dir +mkdir -p $temp_dst_smali_patched_dir +mkdir -p $reject_dir + +cp -r $old_smali_dir/$appname $temp_old_smali_dir +cp -r $dst_smali_dir/$appname $temp_dst_smali_orig_dir +if [ "$suffix" = "jar" ];then + cp -r $new_smali_dir/$appname.jar.out $temp_new_smali_dir/$appname +else + cp -r $new_smali_dir/$appname $temp_new_smali_dir +fi + +$PORT_ROOT/tools/rmline.sh $temp_dir + +function apply_miui_patch() { + old_code_noline=$temp_old_smali_dir/$1 + new_code_noline=$temp_new_smali_dir/$1 + dst_code_noline=$temp_dst_smali_orig_dir/$1 + dst_code=$dst_smali_dir/$1 + dst_code_orig=$dst_code.orig + + echo ">>> compute the difference between $old_code_noline and $new_code_noline" + cd $old_code_noline + for file in `find ./ -name "*.[sx]*"` + do + if [ -f $new_code_noline/$file ] + then + diff $file $new_code_noline/$file > /dev/null || { + diff -B -c $file $new_code_noline/$file > $file.diff + } + else + echo "$file does not exist at $new_code_noline" + fi + done + + cd $dst_smali_dir + mv $dst_code $dst_code_orig + cp -r $dst_code_noline $dst_code + + echo ">>> apply the patch into the $dst_code" + cd $old_code_noline + for file in `find ./ -name "*.diff"` + do + mkdir -p $reject_dir/$1/`dirname $file` + patch $dst_code/${file%.diff} -r $reject_dir/$1/${file%.diff}.rej < $file + done + + cp -r $dst_code $temp_dst_smali_patched_dir + + cd $dst_code_noline + for file in `find ./ -name "*.smali"` + do + rm -f $file.diff + diff -B -c $file $dst_code_orig/$file > $file.diff + patch -f $dst_code/$file -r /dev/null < $file.diff >/dev/null 2>&1 + rm -f $file.diff + done + + find $dst_code -name "*.smali.orig" -exec rm {} \; + find $temp_dst_smali_patched_dir -name "*.smali.orig" -exec rm {} \; + rm -rf $dst_code_orig +} + +apply_miui_patch $appname + +echo ">>> copy out the result smali files and clean the workspace" +mv $new_smali_dir/$appname $new_smali_dir/$appname-old +mv $dst_smali_dir/$appname $new_smali_dir/$appname +rm -rf $old_smali_dir +rm -rf $dst_smali_dir + +echo "<<< patch miui into target $app is done." +echo "Please look at $reject_dir to resolve any conflicts!" +tree -f $reject_dir diff --git a/deodex.sh b/deodex.sh new file mode 100755 index 0000000..4e3da55 --- /dev/null +++ b/deodex.sh @@ -0,0 +1,124 @@ +#!/bin/bash + +TOOL_PATH=$PORT_ROOT/tools +SMALI=$TOOL_PATH/smali +BAKSMALI=$TOOL_PATH/baksmali + +function deodex_one_file() { + if [ "$1" = '-a' ] + then + apilevel=$2 + classpath=$3 + file=$4 + tofile=${file/odex/$5} + echo "processing $tofile" + $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 -I -x $file || exit -2 + fi + $SMALI out -o classes.dex || exit -2 + jar uf $tofile classes.dex + rm classes.dex + rm -rf out + rm $file + zipalign 4 $tofile $tofile.aligned + mv $tofile.aligned $tofile +} + +#usage +if [ $1 = '--help' ] +then + echo "usage: ./deodex.sh [-a APILevel] absolute_path_to_ota_zip_file" + echo " -a specify APILevel, default Level is 15" + exit 0 +fi + +if [ ! -x $BAKSMALI -o ! -x $SMALI ] +then + echo "Error: Can not find baksmali/smali" + exit -1 +fi + +if [ $1 = '-a' ] +then + apilevel=$2 + stockzip=$3 +else + stockzip=$1 +fi + +temppath=`echo $PWD` +tempdir=`mktemp -p $temppath -d tempdir.XXX` +echo "temp dir: $tempdir" +echo "unzip $stockzip to $tempdir" +unzip -q $stockzip -d $tempdir + +if [ -d $tempdir/system ] +then + cd $tempdir/system +elif [ -d $tempdir/SYSTEM ] +then + cd $tempdir/SYSTEM +else + echo "can't find system or SYSTEM dir in $tempdir" + exit -1 +fi + +ls framework/core.odex > /dev/null +if [ $? -eq 0 ] +then + if [ $1 = '-a' ] + then + deodex_one_file -a $apilevel "" framework/core.odex jar + else + deodex_one_file "" framework/core.odex jar + fi +fi + +for f in framework/*.jar +do + classpath=$classpath:$f +done + +echo "classpath=$classpath" + +ls framework/*.odex > /dev/null +if [ $? -eq 0 ] +then + for file in framework/*.odex + do + if [ $1 = '-a' ] + then + deodex_one_file -a $apilevel $classpath $file jar + else + deodex_one_file $classpath $file jar + fi + done +fi + +ls app/*.odex > /dev/null +if [ $? -eq 0 ] +then + for file in app/*.odex + do + if [ $1 = '-a' ] + then + deodex_one_file -a $apilevel $classpath $file apk + else + deodex_one_file $classpath $file apk + fi + done +fi + +cd $tempdir +echo "zip tmp_target_files" +zip -q -r -y "tmp_target_files" * +echo "replaces $stockzip" +cp -f "tmp_target_files.zip" $stockzip +echo "remove $tempdir" +rm -rf $tempdir +echo "deodex done. deodex zip: $stockzip" diff --git a/diffsmali.sh b/diffsmali.sh new file mode 100755 index 0000000..da46dda --- /dev/null +++ b/diffsmali.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +# NOTE: the options for diff should be after the two filenames +RM_LINE=$PORT_ROOT/tools/rmline.sh + +$RM_LINE $1 +$RM_LINE $2 +# -B -u +diff $* +$RM_LINE -r $1 +$RM_LINE -r $2 diff --git a/fix_9patch_png.sh b/fix_9patch_png.sh new file mode 100755 index 0000000..a0186b3 --- /dev/null +++ b/fix_9patch_png.sh @@ -0,0 +1,59 @@ +#!/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/fix_plurals.sh b/fix_plurals.sh new file mode 100755 index 0000000..48e2c42 --- /dev/null +++ b/fix_plurals.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +resdir=$1 +for file in `find $resdir -name "plurals.xml"` +do + $PORT_ROOT/tools/multi_format_subst.pl $file > temp.xml + cp temp.xml $file +done +rm temp.xml diff --git a/gen_desklayout.pl b/gen_desklayout.pl new file mode 100755 index 0000000..ed16e14 --- /dev/null +++ b/gen_desklayout.pl @@ -0,0 +1,34 @@ +#!/usr/bin/perl + +use strict; + +my ($sedfile, $outdir) = @ARGV; + +my %sed; + +#double check if the file exists +if ( not -f $sedfile ) { + print "sedfile does not exist\n"; + exit; +} + +open(SED, $sedfile); +while () { + if (/^\s*([^\s]+)\/([^\s]+)\s*=\s*([^\s]+)\/([^\s]+)\s*$/) { + $sed{$1} = $3; + $sed{$2} = $4; + } +} +close(SED); + +my @deskfiles=<$outdir/default_workspace*.xml>; + +my $sedstr = "sed "; +foreach my $key (keys %sed) { +#print stderr "$key => $sed{$key} \n"; + $sedstr .= "-e s/\\\"$key\\\"/\\\"$sed{$key}\\\"/g "; +} + +foreach my $file (@deskfiles) { + system("$sedstr $file > $file.new"); +} diff --git a/gen_desktop_layout.sh b/gen_desktop_layout.sh new file mode 100755 index 0000000..1fbf548 --- /dev/null +++ b/gen_desktop_layout.sh @@ -0,0 +1,58 @@ +#1) run command to get the following list, and remove the un-necessary lines => sqlite3 launcher.db "select * from favorites;" +#2) run me to get test.xml and put content to the default.. file. +line='1|com.miui.home:string/default_folder_title_tools||-100|3|2|3|1|1|2|-1||||||||1||0 +3|音乐|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.player/.ui.MusicBrowserActivity;end|-100|3|2|2|1|1|0|-1|||com.miui.player|||||1||0 +4|设置|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.settings/.Settings;end|-100|3|0|3|1|1|0|-1|||com.android.settings|||||1||0 +5|文件管理|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.fileexplorer/.FileExplorerTabActivity;end|-100|3|1|3|1|1|0|-1|||com.android.fileexplorer|||||4||0 +6|系统更新|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.updater/.MainActivity;end|1||||1|1|0|-1|||com.android.updater|||||1||0 +7|时钟|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.deskclock/.DeskClock;end|1||||1|1|0|-1|||com.android.deskclock|||||1||0 +8|备份|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.backup/.BackupActivity;end|1||||1|1|0|-1|||com.miui.backup|||||5||0 +9|流量监控|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.monitor/.MainActivity;end|1||||1|1|0|-1|||com.android.monitor|||||1||0 +10|主题风格|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.thememanager/.ThemeResourceTabActivity;end|-100|3|3|2|1|1|0|-1|||com.android.thememanager|||||5||0 +11|电子市场|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.vending/.AssetBrowserActivity;end|-100|4|1|1|1|1|0|-1|||com.android.vending|||||2||0 +12|Gmail|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.google.android.gm/.ConversationListActivityGmail;end|-100|4|2|1|1|1|0|-1|||com.google.android.gm|||||1||0 +13|日历|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.calendar/.LaunchActivity;end|-100|4|0|2|1|1|0|-1|||com.android.calendar|||||1||0 +14|GoogleTalk|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.google.android.talk/.SigningInActivity;end|-100|4|0|1|1|1|0|-1|||com.google.android.talk|||||2||0 +15|拨号|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.contacts/.activities.TwelveKeyDialer;end|-101|0|0|0|1|1|0|-1|||com.android.contacts|||||7||0 +16|联系人|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.contacts/.activities.PeopleActivity;end|-101|0|1|0|1|1|0|-1|||com.android.contacts|||||4||0 +17|浏览器|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.browser/.BrowserActivity;end|-101||||1|1|0|-1|||com.android.browser|||||6||0 +18|信息|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.mms/.ui.MmsTabActivity;end|-101|0|2|0|1|1|0|-1|||com.android.mms|||||5||0 +19|搜索|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.google.android.googlequicksearchbox/.SearchActivity;end|-100|4|3|1|1|1|0|-1||0|com.google.android.googlequicksearchbox|||||1||0 +20|录像|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.videoplayer/.activity.MainTab;end|-100|4|1|0|1|1|0|-1||0|com.sec.android.app.videoplayer|||||1||0 +21|下载管理|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.providers.downloads.ui/.DownloadList;end|-100|4|3|3|1|1|0|-1||0|com.android.providers.downloads.ui|||||1||0 +22|录音机|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.voicerecorder/.VoiceRecorderMainActivity;end|-100|4|3|0|1|1|0|-1||0|com.sec.android.app.voicerecorder|||||1||0 +23|防打扰|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.antispam/.firewall.FirewallTab;end|-100|4|2|3|1|1|0|-1||0|com.miui.antispam|||||1||0 +24|图库|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.cooliris.media/.Gallery;end|-100|3|1|2|1|1|0|-1||0|com.cooliris.media|||||1||0 +25|计算机|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.calculator/.Calculator;end|-100|4|1|2|1|1|0|-1||0|com.sec.android.app.calculator|||||1||0 +26|用户反馈|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.bugreport/.BugReportActivity;end|1|-1|-1|0|1|1|0|-1||0|com.miui.bugreport|||||1||0 +27|时钟|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.clockpackage/.ClockPackage;end|-100|4|2|2|1|1|0|-1||0|com.sec.android.app.clockpackage|||||1||0 +28|照相机|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.camera/.Camera;end|-100|3|0|2|1|1|0|-1||0|com.sec.android.app.camera|||||2||0 +29|FM收音机|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.fm/.MainActivity;end|-100|4|2|0|1|1|0|-1||0|com.sec.android.app.fm|||||2||0 +30|手电筒|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=net.cactii.flash2/.MainActivity;end|1|-1|-1|0|1|1|0|-1||0|net.cactii.flash2|||||1||0 +31|Superuser|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.noshufou.android.su/.Su;end|1|-1|-1|0|1|1|0|-1||0|com.noshufou.android.su|||||1||0 +32|录音机|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.soundrecorder/.SoundRecorder;end|-100|4|0|0|1|1|0|-1||0|com.android.soundrecorder|||||1||0 +33|指南针|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.compass/.CompassActivity;end|-100|4|0|3|1|1|0|-1||0|com.miui.compass|||||1||0 +34|任务管理器|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.sec.android.app.controlpanel/.activity.JobManagerActivity;end|-100|4|1|3|1|1|0|-1||0|com.sec.android.app.controlpanel|||||1||0 +35|便签|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.notes/.ui.NotesListActivity;end|-100|4|3|2|1|1|0|-1||0|com.miui.notes|||||1||0 +36|应用超市|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.miui.supermarket/.MainTabActivity;end|-100|3|3|3|1|1|0|-1||0|com.miui.supermarket|||||2||0 +37|CWM|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=eu.chainfire.cfroot.cwmmanager/.MainActivity;end|1|-1|-1|0|1|1|0|-1||0|eu.chainfire.cfroot.cwmmanager|||||2||0 +38|搜索|#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.android.quicksearchbox/.SearchActivity;end|1|-1|-1|0|1|1|0|-1||0|com.android.quicksearchbox|||||1||0' + +for l in $line; do + name=`echo $l | cut -f2 -d"|"` + class=`echo $l | cut -f3 -d"|" | sed -e "s/.*component=//" -e "s/;end//" -e "s/\///g"` + c=`echo $l | cut -f4 -d"|"` + screen=`echo $l | cut -f5 -d"|"` + let screen=$screen-2 + x=`echo $l | cut -f6 -d"|"` + y=`echo $l | cut -f7 -d"|"` + package=`echo $l | cut -f14 -d"|"` + if [ -z "$screen" ]; then + screen=-1000 + fi + if [ "$screen" -lt 0 ]; then + echo "" >> test.xml + else + echo "" >> test.xml + fi +done diff --git a/gen_res_conf.sh b/gen_res_conf.sh new file mode 100755 index 0000000..9bae7a4 --- /dev/null +++ b/gen_res_conf.sh @@ -0,0 +1,25 @@ +#!/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/git.apply b/git.apply new file mode 100755 index 0000000..db3ec24 --- /dev/null +++ b/git.apply @@ -0,0 +1,47 @@ +#!/bin/bash + +# this is a git apply command wrapper + +RM_LINE=$PORT_ROOT/tools/rmline.sh + +bin_files=`grep "^ .*| *Bin[ 0-9]\+->[ 0-9]\+" $1 | sed -e "s/|.*$//" -e "s/ //g"` +patch_files=`grep "^ .*\.smali.*|" $1 | sed -e "s/|.*$//" -e "s/ //g"` +files= + +for f in $patch_files; do + if [ -f "$f" ]; then + files="$files $f" + else + dirfile=`find . -path "${f/.../*}"` + #echo find file [$f]: $dirfile + files="$files $dirfile" + fi +done + +for f in $files; do + $RM_LINE $f +done + +git apply --reject $1 + +for f in $files; do + $RM_LINE -r $f + ls $f.rej >/dev/null 2>&1 || rm -f $f.orig +done + +echo +echo +++++++++++ +echo + Summary + +echo +++++++++++ +rej_files=`find . -name "*.rej"` +if [ -n "$rej_files" ]; then + echo + Following patches are rejected and merge is required. + echo $rej_files +fi +if [ -n "$bin_files" ]; then + echo + Binary files need to be copied manully. + echo $bin_files +fi +if [ -z "$ref_files$bin_files" ]; then + echo + Apply patch successfully! +fi diff --git a/git.patch b/git.patch new file mode 100755 index 0000000..f5c554e --- /dev/null +++ b/git.patch @@ -0,0 +1,10 @@ +#!/bin/bash + +# this is a git format-patch command wrapper + +git config --global diff.external $PORT_ROOT/tools/git_smali_diff + +git format-patch --ext-diff --stdout $* + +git config --global --remove-section diff + diff --git a/git_smali_diff b/git_smali_diff new file mode 100755 index 0000000..958f77f --- /dev/null +++ b/git_smali_diff @@ -0,0 +1,11 @@ +#!/bin/bash + +if [ "${1%.smali}" == "$1" ];then + #echo "not smali file" + [ $# -eq 7 ] && diff "$2" "$5" -B -u -La/$1 -Lb/$1 + exit 0 +else + #echo "smali files" + [ $# -eq 7 ] && $PORT_ROOT/tools/diffsmali.sh "$2" "$5" -B -u -La/$1 -Lb/$1 + exit 0 +fi diff --git a/git_upload_no_verify.py b/git_upload_no_verify.py new file mode 100644 index 0000000..e48dc23 --- /dev/null +++ b/git_upload_no_verify.py @@ -0,0 +1,399 @@ +# +# Copyright (C) 2008 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 copy +import re +import sys + +from command import InteractiveCommand +from editor import Editor +from error import HookError, UploadError +from project import RepoHook + +UNUSUAL_COMMIT_THRESHOLD = 5 + +def _ConfirmManyUploads(multiple_branches=False): + if multiple_branches: + print "ATTENTION: One or more branches has an unusually high number of commits." + else: + print "ATTENTION: You are uploading an unusually high number of commits." + print "YOU PROBABLY DO NOT MEAN TO DO THIS. (Did you rebase across branches?)" + answer = raw_input("If you are sure you intend to do this, type 'yes': ").strip() + return answer == "yes" + +def _die(fmt, *args): + msg = fmt % args + print >>sys.stderr, 'error: %s' % msg + sys.exit(1) + +def _SplitEmails(values): + result = [] + for str in values: + result.extend([s.strip() for s in str.split(',')]) + return result + +class Upload(InteractiveCommand): + common = True + helpSummary = "Upload changes for code review" + helpUsage=""" +%prog [--re --cc] []... +""" + helpDescription = """ +The '%prog' command is used to send changes to the Gerrit Code +Review system. It searches for topic branches in local projects +that have not yet been published for review. If multiple topic +branches are found, '%prog' opens an editor to allow the user to +select which branches to upload. + +'%prog' searches for uploadable changes in all projects listed at +the command line. Projects can be specified either by name, or by +a relative or absolute path to the project's local directory. If no +projects are specified, '%prog' will search for uploadable changes +in all projects listed in the manifest. + +If the --reviewers or --cc options are passed, those emails are +added to the respective list of users, and emails are sent to any +new users. Users passed as --reviewers must already be registered +with the code review system, or the upload will fail. + +Configuration +------------- + +review.URL.autoupload: + +To disable the "Upload ... (y/N)?" prompt, you can set a per-project +or global Git configuration option. If review.URL.autoupload is set +to "true" then repo will assume you always answer "y" at the prompt, +and will not prompt you further. If it is set to "false" then repo +will assume you always answer "n", and will abort. + +review.URL.autocopy: + +To automatically copy a user or mailing list to all uploaded reviews, +you can set a per-project or global Git option to do so. Specifically, +review.URL.autocopy can be set to a comma separated list of reviewers +who you always want copied on all uploads with a non-empty --re +argument. + +review.URL.username: + +Override the username used to connect to Gerrit Code Review. +By default the local part of the email address is used. + +The URL must match the review URL listed in the manifest XML file, +or in the .git/config within the project. For example: + + [remote "origin"] + url = git://git.example.com/project.git + review = http://review.example.com/ + + [review "http://review.example.com/"] + autoupload = true + autocopy = johndoe@company.com,my-team-alias@company.com + +review.URL.uploadtopic: + +To add a topic branch whenever uploading a commit, you can set a +per-project or global Git option to do so. If review.URL.uploadtopic +is set to "true" then repo will assume you always want the equivalent +of the -t option to the repo command. If unset or set to "false" then +repo will make use of only the command line option. + +References +---------- + +Gerrit Code Review: http://code.google.com/p/gerrit/ + +""" + + def _Options(self, p): + p.add_option('-t', + dest='auto_topic', action='store_true', + help='Send local branch name to Gerrit Code Review') + p.add_option('--re', '--reviewers', + type='string', action='append', dest='reviewers', + help='Request reviews from these people.') + p.add_option('--cc', + type='string', action='append', dest='cc', + help='Also send email to these email addresses.') + p.add_option('--br', + type='string', action='store', dest='branch', + help='Branch to upload.') + p.add_option('--cbr', '--current-branch', + dest='current_branch', action='store_true', + help='Upload current git branch.') + + # Options relating to upload hook. Note that verify and no-verify are NOT + # opposites of each other, which is why they store to different locations. + # We are using them to match 'git commit' syntax. + # + # Combinations: + # - no-verify=False, verify=False (DEFAULT): + # If stdout is a tty, can prompt about running upload hooks if needed. + # If user denies running hooks, the upload is cancelled. If stdout is + # not a tty and we would need to prompt about upload hooks, upload is + # cancelled. + # - no-verify=False, verify=True: + # Always run upload hooks with no prompt. + # - no-verify=True, verify=False: + # Never run upload hooks, but upload anyway (AKA bypass hooks). + # - no-verify=True, verify=True: + # Invalid + p.add_option('--no-verify', + dest='bypass_hooks', action='store_true', + help='Do not run the upload hook.') + p.add_option('--verify', + dest='allow_all_hooks', action='store_true', + help='Run the upload hook without prompting.') + + def _SingleBranch(self, opt, branch, people): + project = branch.project + name = branch.name + remote = project.GetBranch(name).remote + + key = 'review.%s.autoupload' % remote.review + answer = project.config.GetBoolean(key) + + if answer is False: + _die("upload blocked by %s = false" % key) + + if answer is None: + date = branch.date + list = branch.commits + + print 'Upload project %s/ to remote branch %s:' % (project.relpath, project.revisionExpr) + print ' branch %s (%2d commit%s, %s):' % ( + name, + len(list), + len(list) != 1 and 's' or '', + date) + for commit in list: + print ' %s' % commit + + sys.stdout.write('to %s (y/N)? ' % remote.review) + #answer = sys.stdin.readline().strip() + #answer = answer in ('y', 'Y', 'yes', '1', 'true', 't') + + #if True: + #if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD: + #answer = _ConfirmManyUploads() + + if True: + self._UploadAndReport(opt, [branch], people) + else: + _die("upload aborted by user") + + def _MultipleBranches(self, opt, pending, people): + projects = {} + branches = {} + + script = [] + script.append('# Uncomment the branches to upload:') + for project, avail in pending: + script.append('#') + script.append('# project %s/:' % project.relpath) + + b = {} + for branch in avail: + name = branch.name + date = branch.date + list = branch.commits + + if b: + script.append('#') + script.append('# branch %s (%2d commit%s, %s) to remote branch %s:' % ( + name, + len(list), + len(list) != 1 and 's' or '', + date, + project.revisionExpr)) + for commit in list: + script.append('# %s' % commit) + b[name] = branch + + projects[project.relpath] = project + branches[project.name] = b + script.append('') + + script = [ x.encode('utf-8') + if issubclass(type(x), unicode) + else x + for x in script ] + + script = Editor.EditString("\n".join(script)).split("\n") + + project_re = re.compile(r'^#?\s*project\s*([^\s]+)/:$') + branch_re = re.compile(r'^\s*branch\s*([^\s(]+)\s*\(.*') + + project = None + todo = [] + + for line in script: + m = project_re.match(line) + if m: + name = m.group(1) + project = projects.get(name) + if not project: + _die('project %s not available for upload', name) + continue + + m = branch_re.match(line) + if m: + name = m.group(1) + if not project: + _die('project for branch %s not in script', name) + branch = branches[project.name].get(name) + if not branch: + _die('branch %s not in %s', name, project.relpath) + todo.append(branch) + if not todo: + _die("nothing uncommented for upload") + + many_commits = False + for branch in todo: + if len(branch.commits) > UNUSUAL_COMMIT_THRESHOLD: + many_commits = True + break + if many_commits: + if not _ConfirmManyUploads(multiple_branches=True): + _die("upload aborted by user") + + self._UploadAndReport(opt, todo, people) + + def _AppendAutoCcList(self, branch, people): + """ + Appends the list of users in the CC list in the git project's config if a + non-empty reviewer list was found. + """ + + name = branch.name + project = branch.project + key = 'review.%s.autocopy' % project.GetBranch(name).remote.review + raw_list = project.config.GetString(key) + if not raw_list is None and len(people[0]) > 0: + people[1].extend([entry.strip() for entry in raw_list.split(',')]) + + def _FindGerritChange(self, branch): + last_pub = branch.project.WasPublished(branch.name) + if last_pub is None: + return "" + + refs = branch.GetPublishedRefs() + try: + # refs/changes/XYZ/N --> XYZ + return refs.get(last_pub).split('/')[-2] + except: + return "" + + def _UploadAndReport(self, opt, todo, original_people): + have_errors = False + for branch in todo: + try: + people = copy.deepcopy(original_people) + self._AppendAutoCcList(branch, people) + + # Check if there are local changes that may have been forgotten + if branch.project.HasChanges(): + key = 'review.%s.autoupload' % branch.project.remote.review + answer = branch.project.config.GetBoolean(key) + + # if they want to auto upload, let's not ask because it could be automated + if answer is None: + sys.stdout.write('Uncommitted changes in ' + branch.project.name + ' (did you forget to amend?). Continue uploading? (y/N) ') + a = sys.stdin.readline().strip().lower() + if a not in ('y', 'yes', 't', 'true', 'on'): + print >>sys.stderr, "skipping upload" + branch.uploaded = False + branch.error = 'User aborted' + continue + + # Check if topic branches should be sent to the server during upload + if opt.auto_topic is not True: + key = 'review.%s.uploadtopic' % branch.project.remote.review + opt.auto_topic = branch.project.config.GetBoolean(key) + + branch.UploadForReview(people, auto_topic=opt.auto_topic) + branch.uploaded = True + except UploadError, e: + branch.error = e + branch.uploaded = False + have_errors = True + + print >>sys.stderr, '' + print >>sys.stderr, '----------------------------------------------------------------------' + + if have_errors: + for branch in todo: + if not branch.uploaded: + if len(str(branch.error)) <= 30: + fmt = ' (%s)' + else: + fmt = '\n (%s)' + print >>sys.stderr, ('[FAILED] %-15s %-15s' + fmt) % ( + branch.project.relpath + '/', \ + branch.name, \ + str(branch.error)) + print >>sys.stderr, '' + + for branch in todo: + if branch.uploaded: + print >>sys.stderr, '[OK ] %-15s %s' % ( + branch.project.relpath + '/', + branch.name) + + if have_errors: + sys.exit(1) + + def Execute(self, opt, args): + project_list = self.GetProjects(args) + pending = [] + reviewers = [] + cc = [] + branch = None + + if opt.branch: + branch = opt.branch + + for project in project_list: + if opt.current_branch: + cbr = project.CurrentBranch + avail = [project.GetUploadableBranch(cbr)] if cbr else None + else: + avail = project.GetUploadableBranches(branch) + if avail: + pending.append((project, avail)) + + if pending and (not opt.bypass_hooks): + hook = RepoHook('pre-upload', self.manifest.repo_hooks_project, + self.manifest.topdir, abort_if_user_denies=True) + pending_proj_names = [project.name for (project, avail) in pending] + try: + hook.Run(opt.allow_all_hooks, project_list=pending_proj_names) + except HookError, e: + print >>sys.stderr, "ERROR: %s" % str(e) + return + + if opt.reviewers: + reviewers = _SplitEmails(opt.reviewers) + if opt.cc: + cc = _SplitEmails(opt.cc) + people = (reviewers,cc) + + if not pending: + print >>sys.stdout, "no branches ready for upload" + elif len(pending) == 1 and len(pending[0][1]) == 1: + self._SingleBranch(opt, pending[0][1][0], people) + else: + self._MultipleBranches(opt, pending, people) diff --git a/merge_divide_jar_out.sh b/merge_divide_jar_out.sh new file mode 100755 index 0000000..6c67748 --- /dev/null +++ b/merge_divide_jar_out.sh @@ -0,0 +1,80 @@ +#!/bin/bash + +#{JAR_DIVIDE}:i9100:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:sensation:framework.jar.out|widget.jar.out +#{JAR_DIVIDE}:razr:framework.jar.out|framework-ext.jar.out +#{JAR_DIVIDE}:vivo:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:i9300:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:gnote:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:onex:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:ones:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:x515m:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:saga:framework.jar.out|framework2.jar.out +#{JAR_DIVIDE}:me865:framework.jar.out|framework-ext.jar.out +#{JAR_DIVIDE}:lu6200:framework.jar.out|framework2.jar.out + +ANDROID_PATH=$PORT_ROOT/android +PATCH_SH=$PORT_ROOT/tools/merge_divide_jar_out.sh +PATCH_SWAP_PATH=$PORT_ROOT/android/patch + +function error_exit { + echo -e "ERROR: $1" + exit 1 +} + +function merge_jar { + local phone="$1" + local OLD_PWD=$PWD + local config=`grep "#{JAR_DIVIDE}:$phone:" $PATCH_SH | sed "s/#{JAR_DIVIDE}:$1://g"` + if [ -z "$config" ];then + return + fi + + local jar_out=`echo "$config" | cut -d'|' -f1` + local divide_jar_out=`echo "$config" | cut -d'|' -f2` + + cd $PORT_ROOT/$phone + #git checkout . >/dev/null + #git clean -df >/dev/null + + cd $PORT_ROOT/$phone/$divide_jar_out/smali + mkdir $PATCH_SWAP_PATH/divide_jar/ -p + find -type f >"$PATCH_SWAP_PATH/divide_jar/$phone:$jar_out:$divide_jar_out" + cp $PORT_ROOT/$phone/$divide_jar_out/smali/ $PORT_ROOT/$phone/$jar_out/ -r + rm $PORT_ROOT/$phone/$divide_jar_out/smali/ -rf + cd $OLD_PWD +} + +function divide_jar { + local phone="$1" + local OLD_PWD="$PWD" + local recovery_file="`find $PATCH_SWAP_PATH/divide_jar/ -name $phone:*`" + if [ -z "$recovery_file" ];then + return + fi + local jar_out=`basename "$recovery_file" | cut -d':' -f2` + local divide_jar_out=`echo "$recovery_file" | cut -d':' -f3` + OLD_IFS="$IFS" + IFS=$'\n' + for f in `cat "$recovery_file"` + do + dir=`dirname $f` + mkdir $PORT_ROOT/$phone/$divide_jar_out/smali/$dir -p + mv "$PORT_ROOT/$phone/$jar_out/smali/$f" "$PORT_ROOT/$phone/$divide_jar_out/smali/$f" + done + IFS="$OLD_IFS" + rm "$recovery_file" + cd "$PORT_ROOT/$phone" + git clean -df >/dev/null + cd "$OLD_PWD" +} + +######START####### +[ -z "$PORT_ROOT" ] && error_exit "Please setup environment firstly" +[[ ! -d "$PORT_ROOT/$2" || -z "$2" ]] && error_exit "$2 is wrong phone's name" +if [ "$1" = "-m" ];then + merge_jar $2 +elif [ "$1" = "-d" ];then + divide_jar $2 +fi + diff --git a/mkbootfs b/mkbootfs new file mode 100755 index 0000000..31775fb Binary files /dev/null and b/mkbootfs differ diff --git a/mkbootimg b/mkbootimg new file mode 100755 index 0000000..6ff4b84 Binary files /dev/null and b/mkbootimg differ diff --git a/multi_format_subst.pl b/multi_format_subst.pl new file mode 100755 index 0000000..25e787f --- /dev/null +++ b/multi_format_subst.pl @@ -0,0 +1,20 @@ +#!/usr/bin/perl + +use strict; + +open(FILE, $ARGV[0]); + +while( my $line = ) { + + my $n = 0; + while ( $line =~ /%d/ ) { + $n++; + $line =~ s/%d/%$n\$d/; + } + + if ($n==1) { + $line =~ s/%1\$d/%d/ + } + + print $line; +} diff --git a/patch_for_phones.sh b/patch_for_phones.sh new file mode 100755 index 0000000..31f414f --- /dev/null +++ b/patch_for_phones.sh @@ -0,0 +1,442 @@ +#!/bin/bash + +if [ -z "$PORT_ROOT" ] +then + echo -e "\033[91m Please setup environmant firstly \033[1;m" #RED COLOR + echo + exit +fi + +ALL_PHONES=$(sed -n '2p' $PORT_ROOT/build/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) +HTC=(sensation x515m vivo saga onex ones) +HUAWEI=(honor p1 d1) +SONY=(lt18i lt26i) +MOTO=(razr me865) +SAMSUNG=(i9100 i9300 gnote) + +GIT_UPLOAD_TOOL_PATH=$PORT_ROOT/.repo/repo/subcmds +GIT_UPLOAD_TOOL_NO_VERIFY=$PORT_ROOT/tools/git_upload_no_verify.py +PATCH_SH=$PORT_ROOT/tools/patch_for_phones.sh +PATCH_SWAP_PATH=$PORT_ROOT/android/patch +MERGE_DIVIDE_TOOLS=$PORT_ROOT/tools/merge_divide_jar_out.sh + +WHITE='\033[37m' +GRAY='\033[30m' +BLUE='\033[34m' +GREEN='\033[92m' +YELLOW='\033[33m' +RED='\033[91m' +ENDC='\033[1;m' + +ERROR="${RED}ERROR$ENDC" + +TOOL_NAME=${0##*/} +TARGETS= +COMMIT_ARRAY= +TMP_DIR= +STASH= +STASH_MSG="STASH CHANGE FOR AUTO_PATCHING" +BRANCH="for-upload" +RESULT= +COMMIT_MSG= +UPLOAD= + +POS='\033[' +ENDP='H' +LNUM= +CNUM=20 + + +get_line_num() +{ + local pos + echo -ne '\e[6n'; read -sdR pos + pos=${pos#*[} + LNUM=${pos%%;*} + #col=${pos##*;} +} + +function check_commits_parameter { + local phone="$1" + local pre="$2" + local post="$3" + local all_commit + + [ ${#pre} -ne 7 ] && error_exit "length of \"$pre\" is not 7 chars" + [ ${#post} -ne 7 ] && error_exit "length of \"$post\" is not 7 chars" + + all_commit=$(git log --oneline | cut -d' ' -f1) + [ "$pre" = "$post" ] && error_exit "commit NO. is same" + + echo $all_commit | grep -q "$pre" || error_exit "can't find commit $pre" + echo $all_commit | grep -q "$post" || error_exit "can't find commit $post" + + for commit in $all_commit + do + echo $commit | grep -q $pre && error_exit "$pre is ahead than $post" + echo $commit | grep -q $post && break + done +} + +function get_commit_array { + local phone="$1" + local pre="$2" + local post="$3" + local array + + cd "$PORT_ROOT/$phone" + local all_commit=$(git log --oneline | cut -d' ' -f1) + + array=$(echo $all_commit | sed -e "s/$pre.*$//g" | sed -e "s/^.*$post//g") + eval array="($post $array)" + + local len=${#array[*]} + for ((i = 0; i < $len; i++)) + do + COMMIT_ARRAY[$i]=${array[(($len-$i-1))]} + done +} + +function replace_git_upload_tool { + cp $GIT_UPLOAD_TOOL_NO_VERIFY $GIT_UPLOAD_TOOL_PATH/upload.py +} + +function recovery_git_upload_tool { + cd $GIT_UPLOAD_TOOL_PATH + git checkout . 2>/dev/null 1>/dev/null + cd - 2>/dev/null 1>/dev/null +} + +function backup_untracked_files { + local l1=$(git status | grep -n "# Untracked files:" | cut -d':' -f1) + ((l1=l1+3)) + local l2=$(git status | wc -l) + local files=$(git status | sed -n "${l1},${l2}p" | grep -E "^#\s+" |sed "s/#//g") + for f in $files + do + mkdir -p $TMP_DIR/$(dirname $f)/ + mv $f $TMP_DIR/$(dirname $f)/ + done +} + +function stash_changes { + STASH="[stashed]" + git stash save "$STASH_MSG" 1>/dev/null 2>/dev/null +} + +function backup { + grep -q "tmp.*" .git/info/exclude || echo "tmp.*" >> .git/info/exclude + TMP_DIR=$(mktemp -d tmp.XXX) + git status | grep -q "# Untracked files:" && backup_untracked_files + + STASH= + git status | grep -q -E "(# Changes to be committed:|# Changes not staged for commit:)" && stash_changes +} + +function restore { + cp -r $TMP_DIR/* . 2>/dev/null 1>/dev/null + cp -r $TMP_DIR/.[^.]* . 2>/dev/null 1>/dev/null #cp hide files + rm -rf $TMP_DIR +} + +function print_result { + get_line_num + echo -e "$phone ${POS}${LNUM};${CNUM}${ENDP} $result ${YELLOW}${STASH}${ENDC}" +} + +function patch_for_one_phone { + local from="$1" + local phone="$2" + local commit="$3" + local result="success" + + cd "$PORT_ROOT/$phone" + + backup + if ! git checkout "$BRANCH" 2>/dev/null 1>/dev/null + then + result="${RED}failed [no branch $BRANCH]$ENDC" + print_result "$phone" "$result" + restore + return + fi + + if ! repo sync . 2>/dev/null 1>/dev/null + then + result="${RED}failed [sync failed]$ENDC" + print_result "$phone" "$result" + restore + return + fi + + $MERGE_DIVIDE_TOOLS -m $phone + apply_log=$(git.apply $PATCH_SWAP_PATH/$from-patch.$commit 2>&1) + $MERGE_DIVIDE_TOOLS -d $phone + + echo $apply_log | grep -q "error: while searching for:" && result="${RED}failed$ENDC" + echo $apply_log | grep -q -e "error:.*: No such file or directory" && result="${RED}failed$ENDC" + echo $apply_log | grep -q "Rejected" && result="${RED}failed$ENDC" + git status | grep -q "smali.rej" && result="${RED}failed$ENDC" + + if [ $result = "success" ] + then + git add . 2>/dev/null 1>/dev/null + + IFS_OLD="$IFS" + IFS= + echo $MSG | git commit --file=- 2>/dev/null 1>/dev/null + IFS="$IFS_OLD" + + [ $UPLOAD != "false" ] && repo upload . 2>/dev/null 1>/dev/null + else + git clean -df 2>/dev/null 1>/dev/null + git checkout . 2>/dev/null 1>/dev/null + fi + + restore + print_result "$phone" "$result" +} + +function patch_for_phones { + local from="$1" + local to="$2" + local commit="$3" + + for phone in $to + do + patch_for_one_phone "$from" "$phone" "$commit" + done +} + +function patch_one_commit { + local from="$1" + local to="$2" + local commit="$3" + + 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} + IFS_OLD="$IFS" + IFS= + MGS= + MSG=$(git log -1 ${commit} | grep "^\s" | grep -v "Signed-off-by:" | sed "s/\s\+//" | sed "/Change-Id:/d") + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo -ne "" + echo -e "${BLUE}[ID]${ENDC}" + echo " ${commit}" + echo -e "${BLUE}[MSG]${ENDC}" + echo "$MSG" | sed "s/^/ /" + echo ---------------------------------------------------------- + IFS="$IFS_OLD" + #echo "patch_for_phones $from $to ${commit}" + patch_for_phones "$from" "$to" "${commit}" + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo -e "\n" +} + +function patch_commits { + local from="$1" + local to="$2" + local pre="$3" + local post="$4" + + check_commits_parameter $from $pre $post + get_commit_array $from $pre $post + + echo + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo -e " ${BLUE}${#COMMIT_ARRAY[*]}$ENDC COMMITS FROM [${RED}$from$ENDC] NEED TO PATCH:" + echo -n " " + echo -e "${YELLOW}|->${COMMIT_ARRAY[*]}->|$ENDC" + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo + + for ((i = 0; i < ${#COMMIT_ARRAY[*]}; i++)) + do + local commit="${COMMIT_ARRAY[$i]}" + replace_git_upload_tool + + patch_one_commit "$from" "$to" "$commit" + + recovery_git_upload_tool + done +} + +function execute { + local cmdstr="$1" + local cmd + if echo $cmdstr | grep ";" -q + then + for (( i = 1; ; i++ )) + do + cmd=$(echo $cmdstr | cut -d';' -f$i) + [ -z "$cmd" ] && break + echo -e "${YELLOW}++++OUTPUT OF [${GREEN}${cmd}${YELLOW}] @[${GREEN}$(pwd)${YELLOW}]++++$ENDC " + eval $cmd + echo + done + else + echo -e "${YELLOW}++++OUTPUT OF [${GREEN}${cmdstr}${YELLOW}] @[${GREEN}$(pwd)${YELLOW}]++++$ENDC " + eval $cmdstr + fi +} + +function execute_for_phones { + local phones="$1" + local cmdstr="$2" + for phone in $phones + do + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo -e "${BLUE}EXECUTE [$cmdstr] for [$phone]$ENDC" + echo ---------------------------------------------------------- + cd $PORT_ROOT/$phone + execute "$cmdstr" + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo + done +} + +function merge_jar_out_for_phones { + local phones="$1" + + for phone in $phones + do + cd "$PORT_ROOT/$phone" + echo -e "${BLUE}MERGE jar.out for [$phone]$ENDC\n" + $MERGE_DIVIDE_TOOLS "-m" "$phone" + done +} + +function divide_jar_out_for_phones { + local phones="$1" + + for phone in $phones + do + cd "$PORT_ROOT/$phone" + echo -e "${BLUE}DIVIDE jar.out for [$phone]$ENDC\n" + $MERGE_DIVIDE_TOOLS "-d" "$phone" + done +} + +function check_phones { + local invalid + local valid + local t + t="$1" + TARGETS= + for (( i=0; i<${#FACTORYS[*]}; i++ )) + do + if [ "$t" = "${FACTORYS[i]}" ] + then + eval t="$""{""$t""[*]}" + break + fi + done + if [ "$t" = "all" ] + then + t="$ALL_PHONES" + fi + + for p in $t + do + if [[ -d $PORT_ROOT/$p && -n "$p" && -n "$ALL_PHONES" && ${ALL_PHONES/$p/} != ${ALL_PHONES} ]] + then + valid="$valid $p" + else + invalid="$invalid $p" + fi + done + [ -z "$valid" ] && error_exit "no valid targets" + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + [ -n "$invalid" ] && echo -e "${RED}INVALID TARGETS${ENDC}:\n\t$invalid" + TARGETS=$valid + echo -e "${GREEN}VALID TARGETS${ENDC}:" + echo -e "\t$TARGETS" + [ -z "$UPLOAD" ] || echo -e "${GREEN}UPLOAD${ENDC}:\n\t$UPLOAD" + echo ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + echo +} + +function error_exit { + echo -e "$ERROR: $1" + exit 1 +} + +function usage { + echo "*********************************************** USAGE ******************************************************" + echo "$TOOL_NAME [OPTIN]" + echo "OPTION" + echo -e "CASE 1:" + echo -e "\t --exec --phones {\"[phone1 phone2 ... phoneN] or [all]\"} --cmdstr [\"cmdstring\"]" + echo -e "CASE 2:" + echo -e "\t [--without-upload] --patch --from [phone] --to {\"[phone1 phone2 ... phoneN]\" or \"[FACTORY]\" or \"[all]\"} --head [length]" + echo -e "CASE 3:" + echo -e "\t [--without-upload] --patch --from [phone] --to {\"[phone1 phone2 ... phoneN]\" or \"[FACTORY]\" or \"[all]\"} --commits [pre_commit] [post_commit]" + echo -e "CASE 4:" + echo -e "\t --merge-jar-out --phones {\"[phone1 phone2 ... phoneN]\" or \"[FACTORY]\" or \"[all]\"}" + echo -e "CASE 5:" + echo -e "\t --divide-jar-out --phones {\"[phone1 phone2 ... phoneN]\" or \"[FACTORY]\" or \"[all]\"}" + echo + exit $1 +} + + +####start### +case "$1" in + "--exec") + [[ "$2" = "--phones" && "$4" = "--cmdstr" ]] || usage 1 + cd $PORT_ROOT + ALL_PHONES=$(find . -maxdepth 1 -type d | sed "s/\.\///" | grep -v "\.") + check_phones "$3" + cmdstr="$5" + execute_for_phones "$TARGETS" "$cmdstr" + ;; + "--patch" | "--without-upload") + if [ $1 = "--without-upload" ] + then + UPLOAD="false" + shift + else + UPLOAD="true" + fi + + [[ "$1" = "--patch" && "$2" = "--from" && "$4" = "--to" ]] || usage 1 + from="$3" + [ ! -d "$PORT_ROOT/$from" ] && error_exit "[$from] is wrong phone's name" #check from + check_phones "$5" + to="$TARGETS" + cd "$PORT_ROOT/$from" + case "$6" in + "--head") + pre=$(git log --oneline HEAD~$7 -1 | cut -d' ' -f1) + post=$(git log --oneline HEAD -1 | cut -d' ' -f1) + ;; + "--commits") + pre="$7" + post="$8" + ;; + *) + usage 1 + ;; + esac + [[ -z "$pre" || -z "$post" ]] && usage 1 + patch_commits "$from" "$to" "$pre" "$post" + ;; + "--merge-jar-out") + [[ "$2" = "--phones" ]] || usages 1 + check_phones "$3" + merge_jar_out_for_phones "$TARGETS" + ;; + "--divide-jar-out") + [[ "$2" = "--phones" ]] || usages 1 + check_phones "$3" + divide_jar_out_for_phones "$TARGETS" + ;; + *) + usage 1 + ;; +esac + diff --git a/patch_miui_app.sh b/patch_miui_app.sh new file mode 100755 index 0000000..bb4d001 --- /dev/null +++ b/patch_miui_app.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# +# $1: dir for original miui app +# $2: dir for target miui app +# +if [ -f "customize_miui_app.sh" ]; then + ./customize_miui_app.sh $1 $2 + if [ $? -ne 0 ];then + exit 1 + fi +fi + +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 new file mode 100755 index 0000000..96ce5be --- /dev/null +++ b/patch_miui_framework.sh @@ -0,0 +1,91 @@ +#!/bin/bash + +# $1: the old smali code $2: the new smali code $3: the destination smali code + +if [ $# -ne 3 ];then + echo "Usage: patchmiui.sh old_smali_dir new_smali_dir dst_smali_dir" +fi + +PWD=`pwd` +old_smali_dir=$1 +new_smali_dir=$2 +dst_smali_dir=$3 +temp_dir=$PWD/temp +temp_old_smali_dir=$temp_dir/old_smali +temp_new_smali_dir=$temp_dir/new_smali +temp_dst_smali_orig_dir=$temp_dir/dst_smali_orig +temp_dst_smali_patched_dir=$temp_dir/dst_smali_patched +reject_dir=$temp_dir/reject + +rm -rf $temp_dir + +echo "<<< create temp directory to store the old, new source and destination smali code with .line removed" +mkdir -p $temp_old_smali_dir +mkdir -p $temp_new_smali_dir +mkdir -p $temp_dst_smali_orig_dir +mkdir -p $temp_dst_smali_patched_dir +mkdir -p $reject_dir + +cp -r $old_smali_dir/*.jar.out $temp_old_smali_dir +cp -r $new_smali_dir/*.jar.out $temp_new_smali_dir +cp -r $dst_smali_dir/*.jar.out $temp_dst_smali_orig_dir +$PORT_ROOT/tools/rmline.sh $temp_dir + +function apply_miui_patch() { + old_code_noline=$temp_old_smali_dir/$1 + new_code_noline=$temp_new_smali_dir/$1 + dst_code_noline=$temp_dst_smali_orig_dir/$1 + dst_code=$dst_smali_dir/$1 + dst_code_orig=$dst_code.orig + + echo "<<< compute the difference between $old_code_noline and $new_code_noline" + cd $old_code_noline + for file in `find ./ -name "*.smali"` + do + if [ -f $new_code_noline/$file ] + then + diff $file $new_code_noline/$file > /dev/null || { + diff -B -c $file $new_code_noline/$file > $file.diff + } + else + echo "$file does not exist at $new_code_noline" + fi + done + + cd $dst_smali_dir + mv $dst_code $dst_code_orig + cp -r $dst_code_noline $dst_code + + echo "<<< apply the patch into the $dst_code" + cd $old_code_noline + for file in `find ./ -name "*.smali.diff"` + do + mkdir -p $reject_dir/$1/`dirname $file` + patch $dst_code/${file%.diff} -r $reject_dir/$1/${file%.diff}.rej < $file + done + + cp -r $dst_code $temp_dst_smali_patched_dir + + cd $dst_code_noline + for file in `find ./ -name "*.smali"` + do + rm -f $file.diff + diff -B -c $file $dst_code_orig/$file > $file.diff + patch -f $dst_code/$file -r /dev/null < $file.diff >/dev/null 2>&1 + rm -f $file.diff + done + + find $dst_code -name "*.smali.orig" -exec rm {} \; + find $temp_dst_smali_patched_dir -name "*.smali.orig" -exec rm {} \; + rm -rf $dst_code_orig +} + +jar_outs=`grep -rn "JAR_OUTS" $new_smali_dir/README | cut -d'=' -f2` +for out in $jar_outs +do + apply_miui_patch $out +done + +echo +echo +echo ">>> patch miui into target framework is done. Please look at $reject_dir to resolve any conflicts!" diff --git a/prepare_preloaded_classes.sh b/prepare_preloaded_classes.sh new file mode 100755 index 0000000..5cbcbf7 --- /dev/null +++ b/prepare_preloaded_classes.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +TEMPDIR=out/temp_for_preloaded +JAR_DIR=$(basename $2) +JAR_FILE=${JAR_DIR/.jar.out/}.jar +echo "prepare preloaded for $2" +rm -rf $TEMPDIR/ +if [ -f stockrom/system/framework/${JAR_FILE} ] +then + unzip stockrom/system/framework/${JAR_FILE} -d $TEMPDIR +else + unzip $1 system/framework/${JAR_FILE} -d $TEMPDIR + unzip ${TEMPDIR}/system/framework/${JAR_FILE} -d $TEMPDIR +fi + +if [ -f ${TEMPDIR}/preloaded-classes ] +then + rm -f $2/preloaded-classes + cp ${TEMPDIR}/preloaded-classes $2/ +fi + +rm -rf $TEMPDIR/ +if [ ! -f $3/${JAR_FILE} ] +then + exit 0 +fi + +unzip $3/${JAR_FILE} -d $TEMPDIR +if [ -f ${TEMPDIR}/preloaded-classes ] +then + cat ${TEMPDIR}/preloaded-classes >> $2/preloaded-classes + sort $2/preloaded-classes | uniq | grep -v "#" | sed '/^\s*$/d' > $2/temp + cp $2/temp $2/preloaded-classes +fi +rm -rf $TEMPDIR/ + diff --git a/release_source.sh b/release_source.sh new file mode 100755 index 0000000..d650549 --- /dev/null +++ b/release_source.sh @@ -0,0 +1,51 @@ +#!/bin/bash +echo "The android source code is located at: $1" +echo "The miui source code is located at: $2" +echo "The released source code would be put at: $3" + +echo "[IMPORTANT] make sure the source codes has been put under $1" + +src_dir=frameworks/base +android=$1/$src_dir +android_rlz=$PORT_ROOT/android/src/$src_dir +miui=$2/$src_dir +release=$3/src/$src_dir + +for mf in `find $miui -name "*.java"` +do + af=${mf/$miui/$android} + if [ -f "$af" ] + then + diff $af $mf > /dev/null || { + #echo $af is different with $mf; + arf=${af/$android/$android_rlz} + mkdir -p `dirname $arf` + cp $af $arf + rf=${mf/$miui/$release} + mkdir -p `dirname $rf` + cp $mf $rf + } + else + echo "Have $mf but $af does not exist!" + fi +done + +for mf in `find $miui -name "*.aidl"` +do + af=${mf/$miui/$android} + if [ -f "$af" ] + then + diff $af $mf > /dev/null || { + #echo $af is different with $mf; + arf=${af/$android/$android_rlz} + mkdir -p `dirname $arf` + cp $af $arf + rf=${mf/$miui/$release} + mkdir -p `dirname $rf` + cp $mf $rf + } + else + echo "Have $mf but $af does not exist!" + fi +done + diff --git a/releasetools/bsdiff b/releasetools/bsdiff new file mode 100755 index 0000000..f915e6b Binary files /dev/null and b/releasetools/bsdiff differ diff --git a/releasetools/common.py b/releasetools/common.py new file mode 100644 index 0000000..c404cef --- /dev/null +++ b/releasetools/common.py @@ -0,0 +1,862 @@ +# Copyright (C) 2008 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 copy +import errno +import getopt +import getpass +import imp +import os +import platform +import re +import shutil +import subprocess +import sys +import tempfile +import threading +import time +import zipfile + +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 + + +def Run(args, **kwargs): + """Create and return a subprocess.Popen object, printing the command + line on the terminal if -v was specified.""" + if OPTIONS.verbose: + print " running: ", " ".join(args) + return subprocess.Popen(args, **kwargs) + + +def CloseInheritedPipes(): + """ Gmake in MAC OS has file descriptor (PIPE) leak. We close those fds + before doing other work.""" + if platform.system() != "Darwin": + return + for d in range(3, 1025): + try: + stat = os.fstat(d) + if stat is not None: + pipebit = stat[0] & 0x1000 + if pipebit != 0: + os.close(d) + except OSError: + pass + + +def LoadInfoDict(zip): + """Read and parse the META/misc_info.txt key/value pairs from the + input target files and return a dict.""" + + d = {} + try: + 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 + + # backwards compatibility: These values used to be in their own + # files. Look for them, in case we're processing an old + # target_files zip. + + if "mkyaffs2_extra_flags" not in d: + try: + 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"] = 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"] = zip.read("META/tool-extensions.txt").strip() + except KeyError: + # ok if extensions don't exist + pass + + try: + data = zip.read("META/imagesizes.txt") + for line in data.split("\n"): + if not line: continue + name, value = line.split(" ", 1) + if not value: continue + if name == "blocksize": + d[name] = value + else: + d[name + "_size"] = value + except KeyError: + pass + + def makeint(key): + if key in d: + d[key] = int(d[key], 0) + + makeint("recovery_api_version") + makeint("blocksize") + makeint("system_size") + makeint("userdata_size") + makeint("recovery_size") + makeint("boot_size") + + d["fstab"] = LoadRecoveryFSTab(zip) + return d + +def LoadRecoveryFSTab(zip): + class Partition(object): + pass + + try: + data = zip.read("RECOVERY/RAMDISK/etc/recovery.fstab") + except KeyError: + print "Warning: could not find RECOVERY/RAMDISK/etc/recovery.fstab in %s." % zip + data = "" + + 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: + p.device2 = None + options = pieces[3] + else: + p.device2 = None + + if options: + options = options.split(",") + for i in options: + if i.startswith("length="): + p.length = int(i[7:]) + else: + print "%s: unknown option \"%s\"" % (p.mount_point, i) + + d[p.mount_point] = p + return d + + +def DumpInfoDict(d): + for k, v in sorted(d.items()): + print "%-25s = (%s) %s" % (k, type(v).__name__, v) + +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 + building the requested image.""" + + if (not os.access(os.path.join(sourcedir, "RAMDISK"), os.F_OK) or + not os.access(os.path.join(sourcedir, "kernel"), os.F_OK)): + return None + + ramdisk_img = tempfile.NamedTemporaryFile() + img = tempfile.NamedTemporaryFile() + + 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" % (targetname,) + assert p2.returncode == 0, "minigzip of %s ramdisk failed" % (targetname,) + + cmd = ["mkbootimg", "--kernel", os.path.join(sourcedir, "kernel")] + + fn = os.path.join(sourcedir, "cmdline") + if os.access(fn, os.F_OK): + cmd.append("--cmdline") + cmd.append(open(fn).read().rstrip("\n")) + + fn = os.path.join(sourcedir, "base") + if os.access(fn, os.F_OK): + cmd.append("--base") + cmd.append(open(fn).read().rstrip("\n")) + + fn = os.path.join(sourcedir, "pagesize") + if os.access(fn, os.F_OK): + cmd.append("--pagesize") + cmd.append(open(fn).read().rstrip("\n")) + + 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),) + + img.seek(os.SEEK_SET, 0) + data = img.read() + + ramdisk_img.close() + img.close() + + return data + + +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 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..." % (prebuilt_name,) + return File.FromLocalFile(name, prebuilt_path) + 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): + """Unzip the given archive into a temporary directory and return the name. + + If filename is of the form "foo.zip+bar.zip", unzip foo.zip into a + temp dir, then unzip bar.zip into that_dir/BOOTABLE_IMAGES. + + Returns (tempdir, zipobj) where zipobj is a zipfile.ZipFile (of the + main file), open for reading. + """ + + tmp = tempfile.mkdtemp(prefix="targetfiles-") + OPTIONS.tempfiles.append(tmp) + + def unzip_to_dir(filename, dirname): + cmd = ["unzip", "-o", "-q", filename, "-d", dirname] + if pattern is not None: + cmd.append(pattern) + p = Run(cmd, stdout=subprocess.PIPE) + p.communicate() + if p.returncode != 0: + raise ExternalError("failed to unzip input target-files \"%s\"" % + (filename,)) + + m = re.match(r"^(.*[.]zip)\+(.*[.]zip)$", filename, re.IGNORECASE) + if m: + unzip_to_dir(m.group(1), tmp) + unzip_to_dir(m.group(2), os.path.join(tmp, "BOOTABLE_IMAGES")) + filename = m.group(1) + else: + unzip_to_dir(filename, tmp) + + return tmp, zipfile.ZipFile(filename, "r") + + +def GetKeyPasswords(keylist): + """Given a list of keys, prompt the user to enter passwords for + those which require them. Return a {key: password} dict. password + will be None if the key has no password.""" + + no_passwords = [] + need_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. + if k in SPECIAL_CERT_STRINGS: + no_passwords.append(k) + continue + + 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: + no_passwords.append(k) + else: + need_passwords.append(k) + devnull.close() + + key_passwords = PasswordManager().GetPasswords(need_passwords) + key_passwords.update(dict.fromkeys(no_passwords, None)) + return key_passwords + + +def SignFile(input_name, output_name, key, password, align=None, + whole_file=False): + """Sign the input_name zip/jar/apk, producing output_name. Use the + given key and password (the latter may be None if the key does not + have a password. + + If align is an integer > 1, zipalign is run to align stored files in + the output zip on 'align'-byte boundaries. + + If whole_file is true, use the "-w" option to SignApk to embed a + signature that covers the whole file in the archive comment of the + zip file. + """ + + if align == 0 or align == 1: + align = None + + if align: + temp = tempfile.NamedTemporaryFile() + sign_name = temp.name + else: + sign_name = output_name + + cmd = ["java", "-Xmx4096m", "-jar", + os.path.join(OPTIONS.search_path, "signapk.jar")] + if whole_file: + cmd.append("-w") + cmd.extend([key + ".x509.pem", key + ".pk8", + input_name, sign_name]) + + p = Run(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + if password is not None: + password += "\n" + p.communicate(password) + if p.returncode != 0: + raise ExternalError("signapk.jar failed: return code %s" % (p.returncode,)) + + if align: + 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,)) + temp.close() + + +def CheckSize(data, target, info_dict): + """Check the data string passed against the max size limit, if + 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] + mount_point = "/" + target + + if info_dict["fstab"]: + if mount_point == "/userdata": mount_point = "/data" + p = info_dict["fstab"][mount_point] + fs_type = p.fs_type + 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 + + +def ReadApkCerts(tf_zip): + """Given a target_files ZipFile, parse the META/apkcerts.txt file + and return a {package: cert} dict.""" + certmap = {} + for line in tf_zip.read("META/apkcerts.txt").split("\n"): + line = line.strip() + if not line: continue + m = re.match(r'^name="(.*)"\s+certificate="(.*)"\s+' + r'private_key="(.*)"$', line) + if m: + name, cert, privkey = m.groups() + if cert in SPECIAL_CERT_STRINGS and not privkey: + certmap[name] = cert + 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 + + +COMMON_DOCSTRING = """ + -p (--path) + Prepend /bin to the list of places to search for binaries + run by this script, and expect to find jars in /framework. + + -s (--device_specific) + Path to the python module containing device-specific + releasetools code. + + -x (--extra) + Add a key/value pair to the 'extras' dict, which device-specific + extension code may look at. + + -v (--verbose) + Show command lines being executed. + + -h (--help) + Display this usage message and exit. +""" + +def Usage(docstring): + print docstring.rstrip("\n") + print COMMON_DOCSTRING + + +def ParseOptions(argv, + docstring, + extra_opts="", extra_long_opts=(), + extra_option_handler=None): + """Parse the options in argv and return any arguments that aren't + flags. docstring is the calling module's docstring, to be displayed + for errors and -h. extra_opts and extra_long_opts are for flags + defined by the caller, which are processed by passing them to + extra_option_handler.""" + + try: + opts, args = getopt.getopt( + argv, "hvp:s:x:" + extra_opts, + ["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) + sys.exit() + elif o in ("-v", "--verbose"): + OPTIONS.verbose = True + elif o in ("-p", "--path"): + OPTIONS.search_path = a + elif o in ("-s", "--device_specific"): + OPTIONS.device_specific = a + elif o in ("-x", "--extra"): + key, value = a.split("=", 1) + OPTIONS.extras[key] = value + else: + if extra_option_handler is None or not extra_option_handler(o, a): + assert False, "unknown option \"%s\"" % (o,) + + os.environ["PATH"] = (os.path.join(OPTIONS.search_path, "bin") + + os.pathsep + os.environ["PATH"]) + + return args + + +def Cleanup(): + for i in OPTIONS.tempfiles: + if os.path.isdir(i): + shutil.rmtree(i) + else: + os.remove(i) + + +class PasswordManager(object): + def __init__(self): + self.editor = os.getenv("EDITOR", None) + self.pwfile = os.getenv("ANDROID_PW_FILE", None) + + def GetPasswords(self, items): + """Get passwords corresponding to each string in 'items', + returning a dict. (The dict may have keys in addition to the + values in 'items'.) + + Uses the passwords in $ANDROID_PW_FILE if available, letting the + user edit that file to add more needed passwords. If no editor is + available, or $ANDROID_PW_FILE isn't define, prompts the user + interactively in the ordinary way. + """ + + current = self.ReadFile() + + first = True + while True: + missing = [] + for i in 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 + + for i in missing: + current[i] = "" + + if not first: + print "key file %s still missing some passwords." % (self.pwfile,) + answer = raw_input("try to edit again? [y]> ").strip() + if answer and answer[0] not in 'yY': + raise RuntimeError("key passwords unavailable") + first = False + + current = self.UpdateAndReadFile(current) + + 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. + """ + result = {} + for k, v in sorted(current.iteritems()): + if v: + result[k] = v + else: + while True: + result[k] = getpass.getpass("Enter password for %s key> " + % (k,)).strip() + if result[k]: break + return result + + def UpdateAndReadFile(self, current): + if not self.editor or not self.pwfile: + return self.PromptResult(current) + + f = open(self.pwfile, "w") + 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 = [(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. + first_line = i + 4 + f.close() + + p = Run([self.editor, "+%d" % (first_line,), self.pwfile]) + _, _ = p.communicate() + + return self.ReadFile() + + def ReadFile(self): + 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 + 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, e: + if e.errno != errno.ENOENT: + print "error reading password file: ", str(e) + return result + + +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 + module.""" + 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 + try: + if os.path.isdir(path): + info = imp.find_module("releasetools", [path]) + else: + d, f = os.path.split(path) + b, x = os.path.splitext(f) + if x == ".py": + f = b + info = imp.find_module(f, [d]) + 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: + return kwargs.get("default", None) + else: + return ret + #END + + def FullOTA_Assertions(self): + """Called after emitting the block of assertions at the top of a + full OTA package. Implementations can add whatever additional + assertions they like.""" + return self._DoCall("FullOTA_Assertions") + + 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.""" + return self._DoCall("FullOTA_InstallEnd") + + def IncrementalOTA_Assertions(self): + """Called after emitting the block of assertions at the top of an + incremental OTA package. Implementations can add whatever + additional assertions they like.""" + return self._DoCall("IncrementalOTA_Assertions") + + 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_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 + self.data = data + self.size = len(data) + self.sha1 = sha1(data).hexdigest() + + @classmethod + def FromLocalFile(cls, name, diskname): + f = open(diskname, "rb") + data = f.read() + f.close() + return File(name, data) + + def WriteToTemp(self): + t = tempfile.NamedTemporaryFile() + t.write(self.data) + t.flush() + return t + + def AddToZip(self, z): + ZipWriteStr(z, self.name, self.data) + +DIFF_PROGRAM_BY_EXT = { + ".gz" : "imgdiff", + ".zip" : ["imgdiff", "-z"], + ".jar" : ["imgdiff", "-z"], + ".apk" : ["imgdiff", "-z"], + ".img" : "imgdiff", + } + +class Difference(object): + def __init__(self, tf, sf): + self.tf = tf + self.sf = sf + self.patch = None + + def ComputePatch(self): + """Compute the patch (as a string of data) needed to turn sf into + tf. Returns the same tuple as GetPatch().""" + + tf = self.tf + sf = self.sf + + if tf.name.startswith("data/preinstall_apps"): + return self.tf, self.sf, self.patch + + ext = os.path.splitext(tf.name)[1] + diff_program = DIFF_PROGRAM_BY_EXT.get(ext, "bsdiff") + + ttemp = tf.WriteToTemp() + stemp = sf.WriteToTemp() + + ext = os.path.splitext(tf.name)[1] + + 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 = p.communicate() + if err or p.returncode != 0: + print "WARNING: failure running %s:\n%s\n" % (diff_program, err) + return None + diff = ptemp.read() + finally: + ptemp.close() + stemp.close() + ttemp.close() + + self.patch = diff + return self.tf, self.sf, self.patch + + + def GetPatch(self): + """Return a tuple (target_file, source_file, patch_data). + patch_data may be None if ComputePatch hasn't been called, or if + computing the patch failed.""" + return self.tf, self.sf, self.patch + + +def ComputeDifferences(diffs): + """Call ComputePatch on all the Difference objects in 'diffs'.""" + print len(diffs), "diffs to compute" + + # Do the largest files first, to try and reduce the long-pole effect. + by_size = [(i.tf.size, i) for i in diffs] + by_size.sort(reverse=True) + by_size = [i[1] for i in by_size] + + lock = threading.Lock() + diff_iter = iter(by_size) # accessed under lock + + def worker(): + try: + lock.acquire() + for d in diff_iter: + lock.release() + start = time.time() + d.ComputePatch() + dur = time.time() - start + lock.acquire() + + tf, sf, patch = d.GetPatch() + if sf.name == tf.name: + name = tf.name + else: + name = "%s (%s)" % (tf.name, sf.name) + if patch is None: + print "patching failed! %s" % (name,) + else: + 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, e: + print e + raise + + # start worker threads; wait for them all to finish. + threads = [threading.Thread(target=worker) + for i in range(OPTIONS.worker_threads)] + for th in threads: + th.start() + while threads: + threads.pop().join() + + +# map recovery.fstab's fs_types to mount/format "partition types" +PARTITION_TYPES = { "yaffs2": "MTD", "mtd": "MTD", "ext3": "EMMC", + "ext4": "EMMC", "emmc": "EMMC", "vfat": "EMMC", + "auto": "EMMC"} + +def GetTypeAndDevice(mount_point, info): + fstab = info["fstab"] + if fstab: + return PARTITION_TYPES[fstab[mount_point].fs_type], fstab[mount_point].device + else: + return None diff --git a/releasetools/edify_generator.py b/releasetools/edify_generator.py new file mode 100644 index 0000000..656eca3 --- /dev/null +++ b/releasetools/edify_generator.py @@ -0,0 +1,273 @@ +# 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 os +import re + +import common + +class EdifyGenerator(object): + """Class to generate scripts in the 'edify' recovery script language + used from donut onwards.""" + + def __init__(self, version, info): + self.script = [] + self.mounts = set() + self.version = version + self.info = info + + def MakeTemporary(self): + """Make a temporary script object whose commands can latter be + appended to the parent script with AppendScript(). Used when the + caller wants to generate script commands out-of-order.""" + x = EdifyGenerator(self.version, self.info) + x.mounts = self.mounts + return x + + @staticmethod + 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 + to format it nicely.""" + indent = cmd.index("(")+1 + out = [] + first = True + x = re.compile("^(.{,%d})\0" % (linelen-indent,)) + while True: + if not first: + out.append(" " * indent) + first = False + m = x.search(cmd) + if not m: + parts = cmd.split("\0", 1) + out.append(parts[0]+"\n") + if len(parts) == 1: + break + else: + cmd = parts[1] + continue + out.append(m.group(1)+"\n") + cmd = cmd[m.end():] + + return "".join(out).replace("\0", " ").rstrip("\n") + + def AppendScript(self, other): + """Append the contents of another script (which should be created + with temporary=True) to this one.""" + self.script.extend(other.script) + + 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 = ('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(('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 = ('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.""" + cmd = ("assert(" + + " ||\0".join(['getprop("ro.bootloader") == "%s"' % (b,) + for b in bootloaders]) + + ");") + self.script.append(self._WordWrap(cmd)) + + def ShowProgress(self, frac, dur): + """Update the progress bar, advancing it over 'frac' over the next + 'dur' seconds. 'dur' may be zero to advance it via SetProgress + commands instead of by time.""" + self.script.append("show_progress(%f, %d);" % (frac, int(dur))) + + def SetProgress(self, frac): + """Set the position of the progress bar within the chunk defined + by the most recent ShowProgress call. 'frac' should be in + [0,1].""" + self.script.append("set_progress(%f);" % (frac,)) + + 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('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 + given *sha1 hashes.""" + self.script.append('assert(sha1_check(read_file("%s")' % (filename,) + + "".join([', "%s"' % (i,) for i in sha1]) + + '));') + + def CacheFreeSpaceCheck(self, amount): + """Check that there's at least 'amount' space that can be made + available on /cache.""" + 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] + 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.""" + self.script.append('package_extract_dir("%s", "%s");' % (src, dst)) + + def Comment(self, comment): + """Write a comment into the update script.""" + self.script.append("") + for i in comment.split("\n"): + self.script.append("# " + i) + self.script.append("") + + def Print(self, message): + """Log a message to the screen (if the logs are visible).""" + self.script.append('ui_print("%s");' % (message,)) + + def FormatPartition(self, partition): + """Format the given partition, specified by its mount point (eg, + "/system").""" + + reserve_size = 0 + fstab = self.info.get("fstab", None) + if fstab: + p = fstab[partition] + self.script.append('format("%s", "%s", "%s", "%s");' % + (p.fs_type, common.PARTITION_TYPES[p.fs_type], + p.device, p.length)) + + def DeleteFiles(self, file_list): + """Delete all files in file_list.""" + if not file_list: return + cmd = "delete(" + ",\0".join(['"%s"' % (i,) for i in file_list]) + ");" + self.script.append(self._WordWrap(cmd)) + + def ApplyPatch(self, srcfile, tgtfile, tgtsize, tgtsha1, *patchpairs): + """Apply binary patches (in *patchpairs) to the given srcfile to + produce tgtfile (which may be "-" to indicate overwriting the + source file.""" + if len(patchpairs) % 2 != 0 or len(patchpairs) == 0: + raise ValueError("bad patches given to ApplyPatch") + cmd = ['apply_patch("%s",\0"%s",\0%s,\0%d' + % (srcfile, tgtfile, tgtsha1, tgtsize)] + for i in range(0, len(patchpairs), 2): + cmd.append(',\0%s, package_extract_file("%s")' % patchpairs[i:i+2]) + cmd.append(');') + cmd = "".join(cmd) + self.script.append(self._WordWrap(cmd)) + + def WriteRawImage(self, mount_point, fn): + """Write the given package file into the partition for the given + mount point.""" + + fstab = self.info["fstab"] + if fstab: + p = fstab[mount_point] + partition_type = common.PARTITION_TYPES[p.fs_type] + args = {'device': p.device, 'fn': fn} + if partition_type == "MTD": + self.script.append( + 'write_raw_image(package_extract_file("%(fn)s"), "%(device)s");' + % args) + elif partition_type == "EMMC": + 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,)) + + def SetPermissions(self, fn, uid, gid, mode): + """Set file ownership and permissions.""" + 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.""" + 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.""" + by_dest = {} + for d, l in symlink_list: + by_dest.setdefault(d, []).append(l) + + 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)) + + 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 UnmountAll(self): + for p in sorted(self.mounts): + self.script.append('unmount("%s");' % (p,)) + self.mounts = set() + + def AddToZip(self, input_zip, output_zip, input_path=None): + """Write the accumulated script to the output_zip file. input_zip + is used as the source for the 'updater' binary needed to run + script. If input_path is not None, it will be used as a local + path for the binary instead of input_zip.""" + + self.UnmountAll() + + common.ZipWriteStr(output_zip, "META-INF/com/google/android/updater-script", + "\n".join(self.script) + "\n") + + if input_path is None: + data = input_zip.read("OTA/bin/updater") + else: + data = open(os.path.join(input_path, "updater")).read() + common.ZipWriteStr(output_zip, "META-INF/com/google/android/update-binary", + data, perms=0755) diff --git a/releasetools/getfilesysteminfo b/releasetools/getfilesysteminfo new file mode 100755 index 0000000..3b65d79 Binary files /dev/null and b/releasetools/getfilesysteminfo differ diff --git a/releasetools/imgdiff b/releasetools/imgdiff new file mode 100755 index 0000000..5cf4cb3 Binary files /dev/null and b/releasetools/imgdiff differ diff --git a/releasetools/miui_releasetools.py b/releasetools/miui_releasetools.py new file mode 100644 index 0000000..3c14b8e --- /dev/null +++ b/releasetools/miui_releasetools.py @@ -0,0 +1,77 @@ + +import common +import copy + +def FullOTA_Assertions(info): + info.script.Mount("/data") + +def IncrementalOTA_Assertions(info): + info.script.Mount("/data") + +def FullOTA_InstallEnd(info): + UnpackData(info.script) + CopyDataFiles(info.input_zip, info.output_zip, info.script) + Relink(info.input_zip, info.output_zip, info.script) + SetPermissions(info.script) + RemoveAbandonedPreinstall(info.script) + + +def IncrementalOTA_InstallEnd(info): + UnpackData(info.script) + Relink(info.target_zip, info.output_zip, info.script) + SetPermissions(info.script) + RemoveAbandonedPreinstall(info.script) + + + +def Relink(input_zip, output_zip, script): + """relink tool to rebuilding cust variant file and cust link +for backward compatibility that update with ota""" + + print "[MIUI CUST] OTA: handle relink" + # copy relink + data = input_zip.read("OTA/bin/relink") + common.ZipWriteStr(output_zip, "META-INF/com/miui/relink", data) + # add to script + script.AppendExtra("package_extract_file(\"META-INF/com/miui/relink\", \"/data/local/tmp/relink\");") + script.AppendExtra("set_perm(0, 0, 0555, \"/data/local/tmp/relink\");") + script.AppendExtra("run_program(\"/data/local/tmp/relink\");") + script.AppendExtra("delete(\"/data/local/tmp/relink\");") + + +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) + common.ZipWriteStr(output_zip, "data/miui/reinstall_apps", "reinstall_apps") + script.AppendExtra("set_perm(1000, 1000, 0666, \"/data/miui/reinstall_apps\");") + + +def UnpackData(script): + script.UnpackPackageDir("data", "/data") + + +def SetPermissions(script): + print "[MIUI CUST] OTA: SetPermissions" + SetPermissionsRecursive(script, "/data/miui/apps", 1000, 1000, 0755, 0644) + SetPermissionsRecursive(script, "/data/miui/cust", 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\");") + diff --git a/releasetools/ota_from_target_files b/releasetools/ota_from_target_files new file mode 100755 index 0000000..c356e6d --- /dev/null +++ b/releasetools/ota_from_target_files @@ -0,0 +1,881 @@ +#!/usr/bin/env python +# +# Copyright (C) 2008 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. + +""" +Given a target-files zipfile, produces an OTA package that installs +that build. An incremental OTA is produced if -i is given, otherwise +a full OTA is produced. + +Usage: ota_from_target_files [flags] input_target_files output_ota_package + + -b (--board_config) + Deprecated. + + -k (--package_key) Key to use to sign the package (default is + the value of default_system_dev_certificate from the input + target-files's META/misc_info.txt, or + "build/target/product/security/testkey" if that value is not + specified). + + For incremental OTAs, the default value is based on the source + target-file, not the target build. + + -i (--incremental_from) + Generate an incremental OTA using the given target-files zip as + the starting build. + + -w (--wipe_user_data) + Generate an OTA package that will wipe the user data partition + when installed. + + -n (--no_prereq) + Omit the timestamp prereq check normally included at the top of + the build scripts (used for developer OTA packages which + legitimately need to go back and forth). + + -e (--extra_script) + Insert the contents of file at the end of the update script. + + -a (--aslr_mode) + Specify whether to turn on ASLR for the package (on by default). +""" + +import sys + +if sys.hexversion < 0x02040000: + print >> sys.stderr, "Python 2.4 or newer is required." + sys.exit(1) + +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 + +OPTIONS = common.OPTIONS +OPTIONS.package_key = None +OPTIONS.incremental_source = None +OPTIONS.require_verbatim = set() +OPTIONS.prohibit_verbatim = set(("system/build.prop",)) +OPTIONS.patch_threshold = 0.95 +OPTIONS.wipe_user_data = False +OPTIONS.omit_prereq = False +OPTIONS.extra_script = None +OPTIONS.aslr_mode = True +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 + x.sort() + return x[-1][1] + + +def IsSymlink(info): + """Return true if the zipfile.ZipInfo object passed in represents a + symlink.""" + 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) == 010 + +class Item: + """Items represent the metadata (user, group, mode) of files and + directories in the system image.""" + ITEMS = {} + def __init__(self, name, dir=False): + self.name = name + self.uid = 0 + self.gid = 0 + self.mode = 0644 + self.dir = dir + if dir: + self.mode = 0755 + + if name: + self.parent = Item.Get(os.path.dirname(name), dir=True) + self.parent.children.append(self) + else: + self.parent = None + 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) + else: + 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) + if length<4: continue + 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) 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): 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.dir + d = self.descendants = {(self.uid, self.gid, self.mode, None): 1} + for i in self.children: + 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) + d[k] = d.get(k, 0) + 1 + + # 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(): + ug[(uid, gid)] = ug.get((uid, gid), 0) + count + ug = MostPopularKey(ug, (0, 0)) + + # 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]) + self.best_subtree = ug + (best_dmode[1], best_fmode[1]) + + return d + + def SetPermissions(self, script): + """Append set_perm/set_perm_recursive commands to 'script' to + set all permissions, users, and groups for the tree of files + rooted at 'self'.""" + + self.CountChildMetadata() + + def recurse(item, current): + # 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.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]: + 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]: + script.SetPermissions("/"+item.name, item.uid, item.gid, item.mode) + + recurse(self, (-1, -1, -1, -1)) + + +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 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 = [] + retouch_files = [] + + for info in input_zip.infolist(): + if info.filename.startswith("SYSTEM/"): + basefilename = info.filename[7:] + if IsSymlink(info): + symlinks.append((input_zip.read(info.filename), + "/system/" + basefilename)) + else: + info2 = copy.copy(info) + fn = info2.filename = "system/" + basefilename + if substitute and fn in substitute and substitute[fn] is None: + continue + if output_zip is not None: + if substitute and fn in substitute: + data = substitute[fn] + else: + data = input_zip.read(info.filename) + 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("/"): + Item.Get(fn[:-1], dir=True) + else: + Item.Get(fn, dir=False) + + symlinks.sort() + return (symlinks, retouch_files) + +def SignOutput(temp_zip_name, output_zip_name): + key_passwords = common.GetKeyPasswords([OPTIONS.package_key]) + pw = key_passwords[OPTIONS.package_key] + + common.SignFile(temp_zip_name, output_zip_name, OPTIONS.package_key, pw, + whole_file=True) + + +def AppendAssertions(script, input_zip): + device = GetBuildProp("ro.product.device", input_zip) + script.AssertDevice(device) + + +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. + + 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. + + Returns an Item for the shell script, which must be made + executable. + """ + + 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) + + boot_type, boot_device = common.GetTypeAndDevice("/boot", OPTIONS.info_dict) + recovery_type, recovery_device = common.GetTypeAndDevice("/recovery", OPTIONS.info_dict) + + 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. + script = edify_generator.EdifyGenerator(3, 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, + input_version=OPTIONS.info_dict["recovery_api_version"], + output_zip=output_zip, + script=script, + input_tmp=OPTIONS.input_tmp, + metadata=metadata, + info_dict=OPTIONS.info_dict) + + if not OPTIONS.omit_prereq: + ts = GetBuildProp("ro.build.date.utc", input_zip) + script.AssertOlderBuild(ts) + + AppendAssertions(script, input_zip) + device_specific.FullOTA_Assertions() + + script.ShowProgress(0.5, 0) + + if OPTIONS.wipe_user_data: + script.FormatPartition("/data") + + script.Print("Formatting system...") + script.Unmount("/system") + script.FormatPartition("/system") + + script.Print("Installing system files...") + script.Mount("/system") + #script.UnpackPackageDir("recovery", "/system") + script.UnpackPackageDir("system", "/system") + + 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) + + 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) + + script.Print("Set permission...") + Item.GetMetadata(input_zip) + Item.Get("system").SetPermissions(script) + + 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.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.UnmountAll() + script.AddToZip(input_zip, output_zip) + WriteMetadata(metadata, output_zip) + + +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 LoadSystemFiles(z): + """Load all the files from SYSTEM/... in a given target-files + ZipFile, and return a dict of {filename: File object}.""" + out = {} + retouch_files = [] + for info in z.infolist(): + 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) + if info.filename.startswith("SYSTEM/lib/") and IsRegular(info): + retouch_files.append(("/system/" + basefilename, + out[fn].sha1)) + # MIUI ADDD: + # load /data/miui files + elif info.filename.startswith("DATA/miui/") 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 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 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) + + 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, + 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) + + 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: + # Target file identical to source. + pass + + common.ComputeDifferences(diffs) + + 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: + 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.AssertSomeFingerprint(source_fp, target_fp) + + source_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.source_tmp, "BOOT") + target_boot = common.GetBootableImage( + "/tmp/boot.img", "boot.img", OPTIONS.target_tmp, "BOOT") + # 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") + target_recovery = common.GetBootableImage( + "/tmp/recovery.img", "recovery.img", OPTIONS.target_tmp, "RECOVERY") + updating_recovery = (source_recovery.data != target_recovery.data) + + # Here's how we divide up the progress bar: + # 0.1 for verifying the start state (PatchCheck calls) + # 0.8 for applying patches (ApplyPatch calls) + # 0.1 for unpacking verbatim files, symlinking, and doing the + # device-specific commands. + + AppendAssertions(script, target_zip) + device_specific.IncrementalOTA_Assertions() + + script.Print("Verifying current system...") + + script.ShowProgress(0.1, 0) + 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 + + for fn, tf, sf, size, patch_sha in patch_list: + # MIUI ADD: + # skip to check /data patch + 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) + _, _, d = d.ComputePatch() + 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) + + 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) + + if patch_list or updating_recovery or updating_boot: + script.CacheFreeSpaceCheck(largest_source_size) + + device_specific.IncrementalOTA_VerifyEnd() + + script.Comment("---- start making changes here ----") + + if OPTIONS.wipe_user_data: + script.Print("Erasing user data...") + script.FormatPartition("/data") + + script.Print("Removing unneeded files...") + 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 = 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...") + 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) + + 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: + # 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. + # + # 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, target_retouch_dummies) = CopySystemFiles(target_zip, None) + + target_symlinks_d = dict([(i[1], i[0]) for i in target_symlinks]) + temp_script = script.MakeTemporary() + Item.GetMetadata(target_zip) + Item.Get("system").SetPermissions(temp_script) + + # 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. + to_delete = [] + for dest, link in source_symlinks: + if link not in target_symlinks_d: + to_delete.append(link) + script.DeleteFiles(to_delete) + + if verbatim_targets: + script.Print("Unpacking new files...") + script.UnpackPackageDir("system", "/system") + + if updating_recovery: + script.Print("Unpacking new recovery...") + script.UnpackPackageDir("recovery", "/system") + + script.Print("Symlinks and permissions...") + + # Create all the symlinks that don't already exist, or point to + # somewhere different than what we want. Delete each symlink before + # creating it, since the 'symlink' command won't overwrite. + to_create = [] + for dest, link in target_symlinks: + if link in source_symlinks_d: + if dest != source_symlinks_d[link]: + to_create.append((dest, link)) + 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). + + if OPTIONS.extra_script is not None: + script.AppendExtra(OPTIONS.extra_script) + + # Patch the build.prop file last, so if something fails but the + # 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...") + 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() + + 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 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 in ("-w", "--wipe_user_data"): + OPTIONS.wipe_user_data = True + elif o in ("-n", "--no_prereq"): + OPTIONS.omit_prereq = True + elif o in ("-e", "--extra_script"): + OPTIONS.extra_script = a + elif o in ("-a", "--aslr_mode"): + if a in ("on", "On", "true", "True", "yes", "Yes"): + OPTIONS.aslr_mode = True + else: + OPTIONS.aslr_mode = 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: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__) + sys.exit(1) + + if OPTIONS.extra_script is not None: + OPTIONS.extra_script = open(OPTIONS.extra_script).read() + + print "unzipping target target-files..." + OPTIONS.input_tmp, input_zip = common.UnzipTemp(args[0]) + + OPTIONS.target_tmp = OPTIONS.input_tmp + OPTIONS.info_dict = common.LoadInfoDict(input_zip) + if OPTIONS.verbose: + print "--- target info ---" + common.DumpInfoDict(OPTIONS.info_dict) + + if OPTIONS.device_specific is None: + OPTIONS.device_specific = OPTIONS.info_dict.get("tool_extensions", None) + if OPTIONS.device_specific is not None: + 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." + + +if __name__ == '__main__': + try: + common.CloseInheritedPipes() + main(sys.argv[1:]) + except common.ExternalError, e: + print + print " ERROR: %s" % (e,) + print + sys.exit(1) diff --git a/releasetools/ota_target_from_phone b/releasetools/ota_target_from_phone new file mode 100755 index 0000000..677b5d7 --- /dev/null +++ b/releasetools/ota_target_from_phone @@ -0,0 +1,303 @@ +#!/bin/bash + +PWD=`pwd` +TOOL_DIR=$PORT_ROOT/tools +OTA_FROM_TARGET_FILES=$TOOL_DIR/releasetools/ota_from_target_files +TARGET_FILES_TEMPLATE_DIR=$TOOL_DIR/target_files_template + +TMP_DIR=$PWD/out +TARGET_FILES_DIR=$TMP_DIR/target_files +RECOVERY_ETC_DIR=$TARGET_FILES_DIR/RECOVERY/RAMDISK/etc +SYSTEM_DIR=$TARGET_FILES_DIR/SYSTEM +META_DIR=$TARGET_FILES_DIR/META +TARGET_FILES_ZIP=$TMP_DIR/target_files.zip + +OUTPUT_OTA_PACKAGE=$PWD/stockrom.zip +OUTPUT_METADATA_DIR=$PWD/metadata + +FULL_OTA_PACKAGE=$2 +MODE=$1 + +# prompt user +function prompt_user { + echo "ota_target_from_phone -n|-r [ota-package]" + echo " -n: run this script in normal mode" + echo " -r: run this script in recovery mode, if you can run adb in recovery mode, use this option" + echo " ota-package: the stock full OTA package which already installed into your phone." + echo " If you can't find a OTA package, this can be empty and we will generate" + echo " a OTA package for you to use for our make process" + echo + echo "Before running this script, please ensure: " + echo "(1) The phone is connected to PC and turn on USB Debug" + echo "(2) The phone has a rooted kernel or have root privilege" + echo + echo "This script will generate two zip files under $OUTPUT_DIR: " + echo "(1) target_files.zip: this is used to generate incremental OTA package" + echo "(2) update.zip: OTA package you can use if you don't have one. This package is ok to install in recovery" + echo +} + +# copy the whole target_files_template dir +function copy_target_files_template { + echo "Copy target file template into current working directory" + rm -rf $TARGET_FILES_DIR + rm -f $TARGET_FILES_ZIP + mkdir -p $TARGET_FILES_DIR + cp -r $TARGET_FILES_TEMPLATE_DIR/* $TARGET_FILES_DIR +} + +# wait for the device to be online or timeout +function wait_for_device_online { + echo "Wait for the device to be online..." + + local timeout=120 + while [ $timeout -gt 0 ] + do + if adb shell ls > /dev/null + then + break + fi + sleep 30 + timeout=$[$timeout - 30] + done + if [ $timeout -eq 0 ];then + echo "Please ensure adb can find your device and then rerun this script." + exit 1 + fi +} + +function ask_for_boot_image { + echo "Warning: the ota package will not contain bootimage!!!" + echo "Maybe you forget to pass the ota-package parameter." + answer="no" + while [ 1 ] + do + echo -n "Are you sure this is really what you want(yes/no):" + read answer + if [ "$answer" == "no" ];then + exit 0 + elif [ "$answer" == "yes" ];then + return + fi + done +} + +# In normal mode, extract the boot image from full ota package +function extract_bootimage { + if [ -z $FULL_OTA_PACKAGE ];then + ask_for_boot_image + return + fi + + echo "Extract bootimage from full ota package" + local tempdir=`mktemp -d dir.XXXXXX` + unzip -q $FULL_OTA_PACKAGE -d $tempdir + for file in boot.img zImage */boot.img */zImage + do + if [ -f $tempdir/$file ];then + cp $tempdir/$file $TARGET_FILES_DIR/BOOTABLE_IMAGES/boot.img + rm -rf $tempdir + return + fi + done + ask_for_boot_image +} + +# In recovery mode, dump the boot image from device +function dump_bootimage { + echo "Dump bootimage from device" + if [ -f dumpimage.sh ];then + ./dumpimage.sh $TARGET_FILES_DIR/BOOTABLE_IMAGES + else + local info=`adb shell cat /etc/recovery.fstab | grep boot | sed -e "s/\s\+/:/g"` + local fstype=`echo $info | cut -d":" -f2` + + if [ "$fstype" == "mtd" ]; then + mtdn=`adb shell cat /proc/mtd | grep boot | cut -f1 -d":"` + device=/dev/$fstype/$mtdn + else + device=`echo $info | cut -d":" -f3` + fi + adb pull $device $TARGET_FILES_DIR/BOOTABLE_IMAGES/boot.img + fi +} + +# In recovery mode, extract the recovery.fstab from device +function extract_recovery_fstab { + echo "Extract recovery.fstab from device" + adb shell cat /etc/recovery.fstab | awk '{print $1 "\t" $2 "\t" $3}'> $RECOVERY_ETC_DIR/recovery.fstab +} + +# In normal mode, build the recovery.fstab from device +function build_recovery_fstab { + if [ -f recovery.fstab ];then + cp recovery.fstab $RECOVERY_ETC_DIR/recovery.fstab + return + elif [ -n "$FULL_OTA_PACKAGE" ];then + echo $FULL_OTA_PACKAGE + echo "You should provide a recovery.fstab file in your working directory." + exit 1 + fi + + echo "Build recovery.fstab from device" + IFS_OLD=$IFS + IFS=$'\n' + cat /dev/null > $RECOVERY_ETC_DIR/recovery.fstab + for line in `adb shell cat /proc/mounts | grep -E "/system|/data|/cache" | cut -d " " -f1-3` + do + mount_fstype=`echo $line | cut -d " " -f2,3` + device=`echo $line | cut -d " " -f1` + echo $mount_fstype $device >> $RECOVERY_ETC_DIR/recovery.fstab + done + IFS=$IFS_OLD +} + +# build apkcerts.txt +function build_apkcerts { + echo "Build apkcerts.txt" + adb pull /data/system/packages.xml $TARGET_FILES_DIR + python $TOOL_DIR/apkcerts.py $TARGET_FILES_DIR/packages.xml $META_DIR/apkcerts.txt + for file in `ls $SYSTEM_DIR/framework/*.apk` + do + apk=`basename $file` + echo "name=\"$apk\" certificate=\"build/target/product/security/platform.x509.pem\" private_key=\"build/target/product/security/platform.pk8\"" >> $META_DIR/apkcerts.txt + done + cat $META_DIR/apkcerts.txt | sort > $META_DIR/temp.txt + mv $META_DIR/temp.txt $META_DIR/apkcerts.txt + rm $TARGET_FILES_DIR/packages.xml +} + +# build filesystem_config.txt from device +function build_filesystem_config { + echo "Run getfilesysteminfo to build filesystem_config.txt" + + 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" + 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 +} + +function remount_system_device { + echo "Remount /system to be writable" + + if adb root | grep "cannot run" > /dev/null;then + device=`adb shell cat /proc/mounts | grep "/system" | cut -d " " -f 1` + echo "You don't have a rooted kernel. Please run the following command mannually" + echo "(1) adb shell" + echo "(2) su" + echo "(3) mount -o remount,rw $device /system" + echo "(3) chmod 0777 /system /system/*" + echo + + answer="no" + while [ $answer != "yes" ] + do + echo -n "If you finish running the above commands on your phone(yes/no):" + read answer + done + if adb shell ls /system/xbin/getfilesysteminfo;then + return + else + if adb push $TOOL_DIR/releasetools/getfilesysteminfo /system/xbin;then + return + else + echo "Please double check your answer and if your phone has root privilege" + exit 1 + fi + fi + else + sleep 1 + adb remount + fi + sleep 1 +} + +# build the SYSTEM dir under target_files +function build_SYSTEM { + echo "Extract the whole /system from device" + adb pull /system $SYSTEM_DIR + find $SYSTEM_DIR -name su | xargs rm -f + find $SYSTEM_DIR -name invoke-as | xargs rm -f + remount_system_device + build_filesystem_config + recover_symlink +} + +# compress the target_files dir into a zip file +function zip_target_files { + echo "Compress the target_files dir into zip file" + cd $TARGET_FILES_DIR + zip -q -r -y $TARGET_FILES_ZIP * + cd - +} + +# build a new full ota package +function build_ota_package { + echo "Build full ota package: $OUTPUT_OTA_PACKAGE" + $OTA_FROM_TARGET_FILES -n -k $PORT_ROOT/build/security/testkey $TARGET_FILES_ZIP $OUTPUT_OTA_PACKAGE +} + +function gen_metadata { + echo "Generate metadata used to build target files..." + local out=$OUTPUT_METADATA_DIR + rm -rf $out + mkdir -p $out + + cp -f $META_DIR/apkcerts.txt $out + cp -f $META_DIR/filesystem_config.txt $out + mv -f $SYSTEM_DIR/linkinfo.txt $out + cp -f $RECOVERY_ETC_DIR/recovery.fstab $out +} + +if [ $# -eq 0 ] || [ $# -gt 2 ];then + prompt_user + exit 1 +fi + +if [ "$MODE" != "-r" ] && [ "$MODE" != "-n" ];then + prompt_user + exit 1 +fi + +wait_for_device_online +copy_target_files_template + +if [ "$MODE" == "-r" ];then + dump_bootimage + extract_recovery_fstab + adb shell mount /system + adb shell mount /data + sleep 1 +else + extract_bootimage + build_recovery_fstab +fi + +build_SYSTEM +build_apkcerts +gen_metadata +zip_target_files +build_ota_package + +if [ "$MODE" == "-r" ];then + adb shell umount /system +fi diff --git a/releasetools/recoverylink.py b/releasetools/recoverylink.py new file mode 100644 index 0000000..e53b078 --- /dev/null +++ b/releasetools/recoverylink.py @@ -0,0 +1,27 @@ +#!/usr/bin/python +import os +import sys + +path = sys.argv[1] +linkfile_path = path + '/SYSTEM/linkinfo.txt' +#print linkfile_path + +try: + file_object = open(linkfile_path) + linelist = file_object.read( ).split() + for line in linelist: + line = line.rstrip() + filepath = line.split('|') + link_name = filepath[0].replace('system', 'SYSTEM') + target = '/' + filepath[1] + rm = 'rm -f ' + path+ '/' + link_name + os.popen(rm) + ln = 'cd ' + path + ';' + 'ln -s ' + target + ' ' + link_name + #print ln + os.popen(ln) +except IOError: + print r"%s isn't exist" % linkfile_path + sys.exit(1) +file_object.close( ) +print r"Recovery link files success" +sys.exit(0) diff --git a/releasetools/sign_target_files_apks b/releasetools/sign_target_files_apks new file mode 100755 index 0000000..fc71b51 --- /dev/null +++ b/releasetools/sign_target_files_apks @@ -0,0 +1,359 @@ +#!/usr/bin/env python +# +# Copyright (C) 2008 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. + +""" +Signs all the APK files in a target-files zipfile, producing a new +target-files zip. + +Usage: sign_target_files_apks [flags] input_target_files output_target_files + + -e (--extra_apks) + Add extra APK name/key pairs as though they appeared in + apkcerts.txt (so mappings specified by -k and -d are applied). + Keys specified in -e override any value for that app contained + in the apkcerts.txt file. Option may be repeated to give + multiple extra packages. + + -k (--key_mapping) + Add a mapping from the key name as specified in apkcerts.txt (the + src_key) to the real key you wish to sign the package with + (dest_key). Option may be repeated to give multiple key + mappings. + + -d (--default_key_mappings) + Set up the following key mappings: + + $devkey/devkey ==> $dir/releasekey + $devkey/testkey ==> $dir/releasekey + $devkey/media ==> $dir/media + $devkey/shared ==> $dir/shared + $devkey/platform ==> $dir/platform + + where $devkey is the directory part of the value of + default_system_dev_certificate from the input target-files's + META/misc_info.txt. (Defaulting to "build/target/product/security" + if the value is not present in misc_info. + + -d and -k options are added to the set of mappings in the order + in which they appear on the command line. + + -o (--replace_ota_keys) + Replace the certificate (public key) used by OTA package + verification with the one specified in the input target_files + zip (in the META/otakeys.txt file). Key remapping (-k and -d) + is performed on this key. + + -t (--tag_changes) <+tag>,<-tag>,... + Comma-separated list of changes to make to the set of tags (in + the last component of the build fingerprint). Prefix each with + '+' or '-' to indicate whether that tag should be added or + removed. Changes are processed in the order they appear. + Default value is "-test-keys,-dev-keys,+release-keys". + +""" + +import sys + +if sys.hexversion < 0x02040000: + print >> sys.stderr, "Python 2.4 or newer is required." + sys.exit(1) + +import cStringIO +import copy +import os +import re +import subprocess +import tempfile +import zipfile + +import common + +OPTIONS = common.OPTIONS + +OPTIONS.extra_apks = {} +OPTIONS.key_map = {} +OPTIONS.replace_ota_keys = False +OPTIONS.tag_changes = ("-test-keys", "-dev-keys", "+release-keys") + +def GetApkCerts(tf_zip): + certmap = common.ReadApkCerts(tf_zip) + + # apply the key remapping to the contents of the file + for apk, cert in certmap.iteritems(): + certmap[apk] = OPTIONS.key_map.get(cert, cert) + + # apply all the -e options, overriding anything in the file + for apk, cert in OPTIONS.extra_apks.iteritems(): + if not cert: + cert = "PRESIGNED" + certmap[apk] = OPTIONS.key_map.get(cert, cert) + + return certmap + + +def CheckAllApksSigned(input_tf_zip, apk_key_map): + """Check that all the APKs we want to sign have keys specified, and + error out if they don't.""" + unknown_apks = [] + for info in input_tf_zip.infolist(): + if info.filename.endswith(".apk"): + name = os.path.basename(info.filename) + if name not in apk_key_map: + unknown_apks.append(name) + if unknown_apks: + print "ERROR: no key specified for:\n\n ", + print "\n ".join(unknown_apks) + print "\nUse '-e =' to specify a key (which may be an" + print "empty string to not sign this apk)." + sys.exit(1) + + +def SignApk(data, keyname, pw): + unsigned = tempfile.NamedTemporaryFile() + unsigned.write(data) + unsigned.flush() + + signed = tempfile.NamedTemporaryFile() + + common.SignFile(unsigned.name, signed.name, keyname, pw, align=4) + + data = signed.read() + unsigned.close() + signed.close() + + return data + + +def SignApks(input_tf_zip, output_tf_zip, apk_key_map, key_passwords): + maxsize = max([len(os.path.basename(i.filename)) + for i in input_tf_zip.infolist() + if i.filename.endswith('.apk')]) + + for info in input_tf_zip.infolist(): + data = input_tf_zip.read(info.filename) + out_info = copy.copy(info) + if info.filename.endswith(".apk"): + name = os.path.basename(info.filename) + key = apk_key_map[name] + if key not in common.SPECIAL_CERT_STRINGS: + print " signing: %-*s (%s)" % (maxsize, name, key) + signed_data = SignApk(data, key, key_passwords[key]) + output_tf_zip.writestr(out_info, signed_data) + else: + # an APK we're not supposed to sign. + print "NOT signing: %s" % (name,) + output_tf_zip.writestr(out_info, data) + elif info.filename in ("SYSTEM/build.prop", + "RECOVERY/RAMDISK/default.prop"): + print "rewriting %s:" % (info.filename,) + new_data = RewriteProps(data) + output_tf_zip.writestr(out_info, new_data) + else: + # a non-APK file; copy it verbatim + output_tf_zip.writestr(out_info, data) + + +def EditTags(tags): + """Given a string containing comma-separated tags, apply the edits + specified in OPTIONS.tag_changes and return the updated string.""" + tags = set(tags.split(",")) + for ch in OPTIONS.tag_changes: + if ch[0] == "-": + tags.discard(ch[1:]) + elif ch[0] == "+": + tags.add(ch[1:]) + return ",".join(sorted(tags)) + + +def RewriteProps(data): + output = [] + for line in data.split("\n"): + line = line.strip() + original_line = line + if line and line[0] != '#': + key, value = line.split("=", 1) + if key == "ro.build.fingerprint": + pieces = value.split("/") + pieces[-1] = EditTags(pieces[-1]) + value = "/".join(pieces) + elif key == "ro.build.description": + pieces = value.split(" ") + assert len(pieces) == 5 + pieces[-1] = EditTags(pieces[-1]) + value = " ".join(pieces) + elif key == "ro.build.tags": + value = EditTags(value) + line = key + "=" + value + if line != original_line: + print " replace: ", original_line + print " with: ", line + output.append(line) + return "\n".join(output) + "\n" + + +def ReplaceOtaKeys(input_tf_zip, output_tf_zip, misc_info): + try: + keylist = input_tf_zip.read("META/otakeys.txt").split() + except KeyError: + raise ExternalError("can't read META/otakeys.txt from input") + + extra_recovery_keys = misc_info.get("extra_recovery_keys", None) + if extra_recovery_keys: + extra_recovery_keys = [OPTIONS.key_map.get(k, k) + ".x509.pem" + for k in extra_recovery_keys.split()] + if extra_recovery_keys: + print "extra recovery-only key(s): " + ", ".join(extra_recovery_keys) + else: + extra_recovery_keys = [] + + mapped_keys = [] + for k in keylist: + m = re.match(r"^(.*)\.x509\.pem$", k) + if not m: + raise ExternalError("can't parse \"%s\" from META/otakeys.txt" % (k,)) + k = m.group(1) + mapped_keys.append(OPTIONS.key_map.get(k, k) + ".x509.pem") + + if mapped_keys: + print "using:\n ", "\n ".join(mapped_keys) + print "for OTA package verification" + else: + devkey = misc_info.get("default_system_dev_certificate", + "build/target/product/security/testkey") + mapped_keys.append( + OPTIONS.key_map.get(devkey, devkey) + ".x509.pem") + print "META/otakeys.txt has no keys; using", mapped_keys[0] + + # recovery uses a version of the key that has been slightly + # predigested (by DumpPublicKey.java) and put in res/keys. + # extra_recovery_keys are used only in recovery. + + p = common.Run(["java", "-jar", + os.path.join(OPTIONS.search_path, "framework", "dumpkey.jar")] + + mapped_keys + extra_recovery_keys, + stdout=subprocess.PIPE) + data, _ = p.communicate() + if p.returncode != 0: + raise ExternalError("failed to run dumpkeys") + common.ZipWriteStr(output_tf_zip, "RECOVERY/RAMDISK/res/keys", data) + + # SystemUpdateActivity uses the x509.pem version of the keys, but + # put into a zipfile system/etc/security/otacerts.zip. + # We DO NOT include the extra_recovery_keys (if any) here. + + tempfile = cStringIO.StringIO() + certs_zip = zipfile.ZipFile(tempfile, "w") + for k in mapped_keys: + certs_zip.write(k) + certs_zip.close() + common.ZipWriteStr(output_tf_zip, "SYSTEM/etc/security/otacerts.zip", + tempfile.getvalue()) + + +def BuildKeyMap(misc_info, key_mapping_options): + for s, d in key_mapping_options: + if s is None: # -d option + devkey = misc_info.get("default_system_dev_certificate", + "build/target/product/security/testkey") + devkeydir = os.path.dirname(devkey) + + OPTIONS.key_map.update({ + devkeydir + "/testkey": d + "/testkey", + devkeydir + "/devkey": d + "/testkey", + devkeydir + "/media": d + "/media", + devkeydir + "/shared": d + "/shared", + devkeydir + "/platform": d + "/platform", + }) + devkeydir = os.path.dirname("cts/tests/appsecurity-tests/certs/cts-testkey1") + OPTIONS.key_map.update({ + devkeydir + "/cts-testkey1": d + "/testkey", + devkeydir + "/cts-testkey2": d + "/testkey", + }) + else: + OPTIONS.key_map[s] = d + + +def main(argv): + + key_mapping_options = [] + + def option_handler(o, a): + if o in ("-e", "--extra_apks"): + names, key = a.split("=") + names = names.split(",") + for n in names: + OPTIONS.extra_apks[n] = key + elif o in ("-d", "--default_key_mappings"): + key_mapping_options.append((None, a)) + elif o in ("-k", "--key_mapping"): + key_mapping_options.append(a.split("=", 1)) + elif o in ("-o", "--replace_ota_keys"): + OPTIONS.replace_ota_keys = True + elif o in ("-t", "--tag_changes"): + new = [] + for i in a.split(","): + i = i.strip() + if not i or i[0] not in "-+": + raise ValueError("Bad tag change '%s'" % (i,)) + new.append(i[0] + i[1:].strip()) + OPTIONS.tag_changes = tuple(new) + else: + return False + return True + + args = common.ParseOptions(argv, __doc__, + extra_opts="e:d:k:ot:", + extra_long_opts=["extra_apks=", + "default_key_mappings=", + "key_mapping=", + "replace_ota_keys", + "tag_changes="], + extra_option_handler=option_handler) + + if len(args) != 2: + common.Usage(__doc__) + sys.exit(1) + + input_zip = zipfile.ZipFile(args[0], "r") + output_zip = zipfile.ZipFile(args[1], "w") + + misc_info = common.LoadInfoDict(input_zip) + + BuildKeyMap(misc_info, key_mapping_options) + + apk_key_map = GetApkCerts(input_zip) + CheckAllApksSigned(input_zip, apk_key_map) + + key_passwords = common.GetKeyPasswords(set(apk_key_map.values())) + SignApks(input_zip, output_zip, apk_key_map, key_passwords) + + if OPTIONS.replace_ota_keys: + ReplaceOtaKeys(input_zip, output_zip, misc_info) + + input_zip.close() + output_zip.close() + + print "done." + + +if __name__ == '__main__': + try: + main(sys.argv[1:]) + except common.ExternalError, e: + print + print " ERROR: %s" % (e,) + print + sys.exit(1) diff --git a/remove_redef.py b/remove_redef.py new file mode 100755 index 0000000..07d8cde --- /dev/null +++ b/remove_redef.py @@ -0,0 +1,39 @@ +#! /usr/bin/env python +""" +This script is very specific for framework-res/res/values/drawables.xml. +Currently ResValuesModify can't process . +use this script to remove multiple definitions +""" +import sys +import xml +import xml.dom +from xml.dom import minidom + +fdir=sys.argv[1] +filename=fdir +"/res/values/drawables.xml" +xmldoc = minidom.parse(filename) +root = xmldoc.firstChild +elements = [ e for e in root.childNodes if e.nodeType == e.ELEMENT_NODE ] +elem_defs = {} +for elem in elements: + name = elem.attributes["name"].value + elem_defs[name] = elem_defs.get(name, 0) + 1 + +repeat_defs = [ name for name in elem_defs.keys() if elem_defs[name] > 1] +xmldoc.unlink() + +f = open(filename, "r") +lines = f.readlines() +f.close() + +for line in lines: + for rdef in repeat_defs: + if rdef in line: + lines.remove(line) + repeat_defs.remove(rdef) + +f = open(filename, "w") +f.writelines(lines) +f.close() + + diff --git a/replace_package_name.sh b/replace_package_name.sh new file mode 100755 index 0000000..511aefc --- /dev/null +++ b/replace_package_name.sh @@ -0,0 +1,34 @@ +#!/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/replace_res_id.pl b/replace_res_id.pl new file mode 100755 index 0000000..658dade --- /dev/null +++ b/replace_res_id.pl @@ -0,0 +1,41 @@ +#!/usr/bin/perl +#=============================================================================== +# FILE: replace_res_id.pl +# +# DESCRIPTION: The resource id in source code is referenced as const of +# R.type.name (i.e. application defined resources), and this script +# would replace them with the value from the specified apk. +# This is useful if we want to insert the piece of code to one APK +# in smali format, e.g. to use our implementation for updateInCallNotification() +# for Phone.apk +# USAGE: replace_res_id.pl source.java dest.apk > source.java.new +# rename source.java.new as source.java to build the APK +#=============================================================================== + +use strict; +use warnings; + +my ($srcfile, $apk) = @ARGV; + +open(SRC, "<$srcfile"); + +while(my $line = ){ + + while ( $line =~ /[^\.]R\.([_\.a-zA-Z0-9]+)/g ) + { + my ($id, $oid) = ($1, $1); + $id =~ s/\./\\\//; + #print("aapt d resources $apk | grep spec.*$id\n"); + my $ret = `aapt d resources $apk | grep spec.*$id:`; + $ret =~ s/^\s*spec\s+resource\s+(0x[0-9a-f]+).*$/$1/; + chomp($ret); + if ($ret) { + $line =~ s/R\.$oid/$ret/; + } + else { + warn "No id found for R.$oid\n"; + } + } + print $line; +} +close(SRC); diff --git a/replace_smali_method.sh b/replace_smali_method.sh new file mode 100755 index 0000000..c48daed --- /dev/null +++ b/replace_smali_method.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +action=$1 +file=$2 +method=$3 +OUT=out + +function get_method_content() { + dir=$1 + file=$2 + method=$3 + + number=`find $dir -name $file.smali | wc -l` + if [ ! "$number" == 1 ]; then + echo "no or more than one file named $file.smali!" + exit -1 + fi + + file=`find $dir -name $file.smali` + + patchfile=`basename $file`.method + patchdir=`dirname $file` + patchdir=`echo $patchdir | sed -e "s/$dir\///"` + + echo patch $file at $patchdir/$patchfile + mkdir -p $patchdir + cat $file | sed -n -e "/^\.method.*$method/,/^\.end method/p" > $patchdir/$patchfile +} + +function apply_method() { + dir=$1 + patch=$2 + + to=$dir/`echo $patch | sed -e "s/.method//"` + # now only support one method in one file + method=`cat $patch | grep "^.method" | sed -e "s/^.* //" -e "s/(.*$//"` + + echo patch method $method to file $to + cat $to | sed -e "/^\.method.*$method/,/^\.end method/d" > $to.patched + cat $patch >> $to.patched + mv $to.patched $to +} + +if [ "$action" == "patch" ]; then + get_method_content $OUT $file $method +fi + +if [ "$action" == "apply" ]; then + apply_method $OUT $file +fi diff --git a/restore_obsolete_keyguard.sh b/restore_obsolete_keyguard.sh new file mode 100755 index 0000000..f07aa54 --- /dev/null +++ b/restore_obsolete_keyguard.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +cd android.policy.jar.out/smali/com/android/internal/policy/impl +cp keyguard_obsolete/*.smali . + + +for class in `find ./keyguard_obsolete -name '*.smali' \ + | sed 's#./keyguard_obsolete/##g' | sed 's#.smali##g' \ + | cut -d$ -f1 | sort | uniq` +do + for smali in `grep -rn $class . | cut -d: -f1 | sort | uniq` + do + sed -i "s/keyguard_obsolete\/$class/$class/g" $smali + sed -i "s/keyguard_obsolete\$$class/$class/g" $smali + done +done + +rm -r ./keyguard_obsolete + +cd - diff --git a/rewrite.py b/rewrite.py new file mode 100755 index 0000000..980bd01 --- /dev/null +++ b/rewrite.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python + +import sys + +if len(sys.argv) != 4: + print("Usage: rewrite filename old-string new-string") + sys.exit(1) + +filename = sys.argv[1] +oldstr = sys.argv[2] +newstr = sys.argv[3] +with open(filename) as f: + content = f.read() + content = content.replace(oldstr, newstr) + +with open(filename, "w") as f: + f.write(content) diff --git a/rmline.sh b/rmline.sh new file mode 100755 index 0000000..22625af --- /dev/null +++ b/rmline.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +who=`whoami` +tmp_loc=/tmp/rmline_$who + +# $2 is the file name with the full absolute path +function rm_line() { + local action=$1 + local file=$2 + local diff_file=$tmp_loc$file.line + + if [ "$action" == "remove" ]; then + mv $file $file.original + more $file.original | sed -e '/^\s*\.line.*$/d' | sed -e 's/\/jumbo//' > $file + diff $file $file.original > /dev/null || { + mkdir -p `dirname $diff_file` + diff -B -c $file $file.original > $diff_file + } + rm $file.original + else + if [ -f $diff_file ]; then + patch -f $file -r /dev/null < $diff_file >/dev/null 2>&1 + rm -f $diff_file + else + echo "Warning: line info file ($diff_file) does not exist" >&2 + fi + fi +} + +action=remove +if [ "$1" == "-r" ]; then + action=add + shift +fi + +p=`pwd` +full=`echo $1 | sed -e "s#\(^[^\/]\)#$p/\1#"` +if [ -f "$full" ]; then + echo $full | grep .smali$ > /dev/null && rm_line $action $full + exit 0 +fi + +for file in `find $full -name "*.smali"` +do + rm_line $action $file +done 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/sign.sh b/sign.sh new file mode 100755 index 0000000..6e54def --- /dev/null +++ b/sign.sh @@ -0,0 +1,102 @@ +#!/bin/bash + +# The path for keys could be set when exec sign.sh as: +# KEY_PATH=/path/to/key sign.sh .. +# If the path is not set, the default value is: +# 1) if PORT_ROOT is set (after running lunch), it is +# $PORT_ROOT/porting/tools +# 2) if not running lunch, the default path is ./ +if [ -z "$PORT_ROOT" ] +then + KEYPATH=${KEY_PATH:=.} +else + KEYPATH=${KEY_PATH:=$PORT_ROOT/build/security} +fi + +SIGNAPK=$PORT_ROOT/tools/signapk.jar +PEMKEY=$KEYPATH/testkey.x509.pem +PK8KEY=$KEYPATH/testkey.pk8 + +TMPDIR=.tmp_for_sign + +function delete_meta_info() { + zip -d $1 "META-INF/*" +} + +function sign_for_phone() { + echo ">>> Sign apks under dir $1..." + for apk in `adb shell ls $1/*.apk | col -b` + do + echo ">>> Sign for $apk" + file=`basename $apk` + adb pull $apk $TMPDIR/$file + delete_meta_info $TMPDIR/$file + java -jar $SIGNAPK $PEMKEY $PK8KEY $TMPDIR/$file $TMPDIR/$file.signed + zipalign 4 $TMPDIR/$file.signed $TMPDIR/$file.signed.aligned + adb push $TMPDIR/$file.signed.aligned $1/$file + done +} + +function sign_for_dir() { + echo ">>> Sign apks under dir $1..." + for apk in `find $1 -name "*.apk"` + do + echo ">>> Sign for $apk" + delete_meta_info $apk + java -jar $SIGNAPK $PEMKEY $PK8KEY $apk $apk.signed + zipalign 4 $apk.signed $apk.signed.aligned + mv $apk.signed.aligned $apk + rm $apk.signed + done +} + +if [ -z "$1" ] +then + echo "usage: ./sign.sh sign.phone - to sign all apks for phone" + echo " ./sign.sh sign.zip dir - to sign all apks for the unzip-ed zip-file" + echo " ./sign.sh apk-file [filename] - to sign apk-file and push to phone as filename" + exit 0 +fi + +if [ "$1" == "sign.phone" ] +then + adb remount || { echo "Failed to remount the device"; exit 10;} + mkdir -p $TMPDIR + sign_for_phone "/system/app" + sign_for_phone "/system/framework" + rm -rf $TMPDIR + echo Siging Complete + exit 0 +fi + +if [ "$1" == "sign.zip" ] +then + ZIP_DIR=$2 + sign_for_dir "$ZIP_DIR/system/app" + sign_for_dir "$ZIP_DIR/system/framework" + echo Siging Complete + exit 0 +fi + +if [ -f "$1" ] +then + SIGNED=$1.signed + ALIGNED=$SIGNED.aligned + delete_meta_info $1 + java -jar $SIGNAPK $PEMKEY $PK8KEY $1 $SIGNED + zipalign 4 $SIGNED $ALIGNED + if [ -n "$2" ] + then + adb remount || { echo "Failed to remount the device"; exit 10;} + echo "push $ALIGNED $2" + adb push $ALIGNED $2 + rm $SIGNED + rm $ALIGNED + else + echo "The Signed file: $SIGNED" + fi + exit 0 +else + echo "Apk file $1 does not exist" + exit 1 +fi diff --git a/signapk.jar b/signapk.jar new file mode 100644 index 0000000..f6fe372 Binary files /dev/null and b/signapk.jar differ diff --git a/smali b/smali new file mode 100755 index 0000000..e8bed94 --- /dev/null +++ b/smali @@ -0,0 +1,77 @@ +#!/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. + +# 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 + +# 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=smali.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="-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 +# 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/smali.jar b/smali.jar new file mode 100644 index 0000000..b2d09e9 Binary files /dev/null and b/smali.jar differ diff --git a/target_files_template/BOOTABLE_IMAGES/recovery.img b/target_files_template/BOOTABLE_IMAGES/recovery.img new file mode 100644 index 0000000..fec9144 Binary files /dev/null and b/target_files_template/BOOTABLE_IMAGES/recovery.img 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 new file mode 100644 index 0000000..943544e --- /dev/null +++ b/target_files_template/META/apkcerts.txt @@ -0,0 +1,438 @@ +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="GameCenterSDKService.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/platform.x509.pem" private_key="build/target/product/security/platform.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="Exchange2.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="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="Userbook.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AirkanPhoneService.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/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="Transfer.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="YellowPage.apk" certificate="build/target/product/security/shared.x509.pem" private_key="build/target/product/security/shared.pk8" +name="BaiduNetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="AtciService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BrRemoteService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="BackupAndRestore.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="MiWallpaper.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="PaymentService.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="AMAPNetworkLocation.apk" certificate="PRESIGNED" private_key="" +name="VoiceRecognizerXunfei.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="KingSoftCleaner.apk" certificate="PRESIGNED" private_key="" +name="baidushurufa_52.apk" certificate="PRESIGNED" private_key="" +name="O2O.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="NetworkAssistant2.apk" certificate="build/target/product/security/platform.x509.pem" private_key="build/target/product/security/platform.pk8" +name="ota-miui-MiShop.apk" certificate="PRESIGNED" private_key="" +name="ota-partner-NetworkAssistant.apk" certificate="PRESIGNED" private_key="" +name="ota-partner-XunfeiSpeechService3.apk" certificate="PRESIGNED" private_key="" +name="MiuiForum.apk" certificate="PRESIGNED" private_key="" +name="MiLinkService.apk" certificate="build/target/product/security/testkey.x509.pem" private_key="build/target/product/security/testkey.pk8" +name="TrafficControl.apk" certificate="PRESIGNED" private_key="" diff --git a/target_files_template/META/filesystem_config.txt b/target_files_template/META/filesystem_config.txt new file mode 100644 index 0000000..7c33b14 --- /dev/null +++ b/target_files_template/META/filesystem_config.txt @@ -0,0 +1,6 @@ +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 1000 6750 +system/xbin/oemfix 0 2000 6755 diff --git a/target_files_template/META/misc_info.txt b/target_files_template/META/misc_info.txt new file mode 100644 index 0000000..33d303e --- /dev/null +++ b/target_files_template/META/misc_info.txt @@ -0,0 +1,7 @@ +recovery_api_version=3 +blocksize=131072 +boot_size=0x00280000 +recovery_size=0x00500000 +system_size=0x08400000 +userdata_size=0x0c440000 +tool_extensions=. diff --git a/target_files_template/META/otakeys.txt b/target_files_template/META/otakeys.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/target_files_template/META/otakeys.txt @@ -0,0 +1 @@ + diff --git a/target_files_template/OTA/android-info.txt b/target_files_template/OTA/android-info.txt new file mode 100644 index 0000000..c4cb15c --- /dev/null +++ b/target_files_template/OTA/android-info.txt @@ -0,0 +1,5 @@ +require mid=P* +require board=mahimahi|nexusone +require version-bootloader=0.35.2017|0.35.0017 +require version-microp=0b15|0c15 +require version-baseband=5.08.00.04 diff --git a/target_files_template/OTA/bin/applypatch b/target_files_template/OTA/bin/applypatch new file mode 100644 index 0000000..577673d Binary files /dev/null and b/target_files_template/OTA/bin/applypatch differ diff --git a/target_files_template/OTA/bin/applypatch_static b/target_files_template/OTA/bin/applypatch_static new file mode 100644 index 0000000..514e92d Binary files /dev/null and b/target_files_template/OTA/bin/applypatch_static differ diff --git a/target_files_template/OTA/bin/check_prereq b/target_files_template/OTA/bin/check_prereq new file mode 100644 index 0000000..79090eb Binary files /dev/null and b/target_files_template/OTA/bin/check_prereq differ diff --git a/target_files_template/OTA/bin/relink b/target_files_template/OTA/bin/relink new file mode 100644 index 0000000..9086eed Binary files /dev/null and b/target_files_template/OTA/bin/relink differ diff --git a/target_files_template/OTA/bin/sqlite3 b/target_files_template/OTA/bin/sqlite3 new file mode 100644 index 0000000..32e6cfd Binary files /dev/null and b/target_files_template/OTA/bin/sqlite3 differ diff --git a/target_files_template/OTA/bin/updater b/target_files_template/OTA/bin/updater new file mode 100644 index 0000000..29fbc64 Binary files /dev/null and b/target_files_template/OTA/bin/updater differ diff --git a/target_files_template/RADIO/bitmap_size.txt b/target_files_template/RADIO/bitmap_size.txt new file mode 100644 index 0000000..8e6f3fc --- /dev/null +++ b/target_files_template/RADIO/bitmap_size.txt @@ -0,0 +1 @@ +480 800 16 diff --git a/target_files_template/RADIO/firmware_error.565 b/target_files_template/RADIO/firmware_error.565 new file mode 100644 index 0000000..ea5c89e Binary files /dev/null and b/target_files_template/RADIO/firmware_error.565 differ diff --git a/target_files_template/RADIO/firmware_install.565 b/target_files_template/RADIO/firmware_install.565 new file mode 100644 index 0000000..95bd146 Binary files /dev/null and b/target_files_template/RADIO/firmware_install.565 differ diff --git a/target_files_template/RECOVERY/RAMDISK/etc/recovery.fstab b/target_files_template/RECOVERY/RAMDISK/etc/recovery.fstab new file mode 100644 index 0000000..9b5387c --- /dev/null +++ b/target_files_template/RECOVERY/RAMDISK/etc/recovery.fstab @@ -0,0 +1,9 @@ +# mount point fstype device [device2] + +/boot mtd boot +/cache yaffs2 cache +/data yaffs2 userdata +/misc mtd misc +/recovery mtd recovery +/sdcard vfat /dev/block/mmcblk0p1 /dev/block/mmcblk0 +/system yaffs2 system diff --git a/target_files_template/SYSTEM/build.prop b/target_files_template/SYSTEM/build.prop new file mode 100644 index 0000000..b5545c8 --- /dev/null +++ b/target_files_template/SYSTEM/build.prop @@ -0,0 +1 @@ +# place holder diff --git a/uniq_first.py b/uniq_first.py new file mode 100755 index 0000000..bbb3404 --- /dev/null +++ b/uniq_first.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +import os +import sys +def uniq_first(src_file, dst_file): + lines = [] + with open(src_file, 'r') as sf: + lines = sf.readlines() + with open(dst_file, 'r') as tf: + content = tf.read() + + with open(dst_file, 'a') as df: + for line in lines: + 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) != 3: + print("Usage: uniq_first src_file dst_file make_dir") + sys.exit(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