Loading util/com/android/launcher3/DecoderRing.java +167 −132 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.launcher3; import com.android.launcher3.backup.BackupProtos; import com.android.launcher3.backup.BackupProtos.CheckedMessage; import com.android.launcher3.backup.BackupProtos.Favorite; import com.android.launcher3.backup.BackupProtos.Key; Loading @@ -35,6 +34,8 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.System; import java.util.LinkedList; import java.util.List; import java.util.zip.CRC32; import javax.xml.bind.DatatypeConverter; Loading @@ -46,7 +47,7 @@ import javax.xml.bind.DatatypeConverter; * <P>When using com.android.internal.backup.LocalTransport, the file names are base64-encoded Key * protocol buffers with a prefix, that have been base64-encoded again by the transport: * <pre> * echo TDpDQUlnL0pxVTVnOD0= | base64 -D | dd bs=1 skip=2 | base64 -D | launcher_protoutil -k * echo "TDpDQUlnL0pxVTVnOD0=" | launcher_protoutil -k * </pre> * * <P>This tool understands these file names and will use the embedded Key to detect the type and Loading @@ -56,13 +57,19 @@ import javax.xml.bind.DatatypeConverter; * </pre> * * <P>With payload debugging enabled, base64-encoded protocol buffers will be written to the logs. * Copy the encoded log snippet into a file, and specify the type explicitly: * Copy the encoded snippet from the log, and specify the type explicitly, with the Logs flags: * <pre> * base64 -D icon.log > icon.bin * launcher_protoutil -i icon.bin * echo "CAEYLiCJ9JKsDw==" | launcher_protoutil -L -k * </pre> * For backup payloads it is more convenient to copy the log snippet to a file: * <pre> * launcher_protoutil -L -f favorite.log * </pre> */ class DecoderRing { public static final String STANDARD_IN = "**stdin**"; private static Class[] TYPES = { Key.class, Favorite.class, Loading @@ -74,24 +81,25 @@ class DecoderRing { public static void main(String[ ] args) throws Exception { File source = null; Class type = null; Class defaultType = null; boolean extractImages = false; boolean fromLogs = false; int skip = 0; List<File> files = new LinkedList<File>(); for (int i = 0; i < args.length; i++) { if ("-k".equals(args[i])) { type = Key.class; defaultType = Key.class; } else if ("-f".equals(args[i])) { type = Favorite.class; defaultType = Favorite.class; } else if ("-j".equals(args[i])) { type = Journal.class; defaultType = Journal.class; } else if ("-i".equals(args[i])) { type = Resource.class; defaultType = Resource.class; } else if ("-s".equals(args[i])) { type = Screen.class; defaultType = Screen.class; } else if ("-w".equals(args[i])) { type = Widget.class; defaultType = Widget.class; } else if ("-S".equals(args[i])) { if ((i + 1) < args.length) { skip = Integer.valueOf(args[++i]); Loading @@ -100,50 +108,44 @@ class DecoderRing { } } else if ("-x".equals(args[i])) { extractImages = true; } else if ("-L".equals(args[i])) { fromLogs = true; } else if (args[i] != null && !args[i].startsWith("-")) { source = new File(args[i]); files.add(new File(args[i])); } else { System.err.println("Unsupported flag: " + args[i]); usage(args); } } if (type == null) { if (source == null) { if (defaultType == null && files.isEmpty()) { // can't infer file type without the key usage(args); } else { Key key = new Key(); try { byte[] rawKey = DatatypeConverter.parseBase64Binary(source.getName()); if (rawKey[0] != 'L' || rawKey[1] != ':') { System.err.println("you must specify the payload type. " + source.getName() + " is not a launcher backup key."); System.exit(1); } String encodedPayload = new String(rawKey, 2, rawKey.length - 2); byte[] keyProtoData = DatatypeConverter.parseBase64Binary(encodedPayload); key = Key.parseFrom(keyProtoData); } catch (InvalidProtocolBufferNanoException protoException) { System.err.println("failed to extract key from filename: " + protoException); System.exit(1); } catch (IllegalArgumentException base64Exception) { System.err.println("failed to extract key from filename: " + base64Exception); System.exit(1); if (files.size() > 1) { System.err.println("Explicit type ignored for multiple files."); defaultType = null; } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key ckecksum failed"); System.exit(1); if (files.isEmpty()) { files.add(new File(STANDARD_IN)); } for (File source : files) { Class type = null; if (defaultType == null) { Key key = decodeKey(source.getName().getBytes(), fromLogs); type = TYPES[key.type]; System.err.println("This is a " + type.getSimpleName() + " backup"); } } else { type = defaultType; } // read in the bytes ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); BufferedInputStream input = null; if (source == null) { if (source.getName() == STANDARD_IN) { input = new BufferedInputStream(System.in); } else { try { Loading Loading @@ -173,43 +175,11 @@ class DecoderRing { } MessageNano proto = null; byte[] payload = byteStream.toByteArray(); if (type == Key.class) { Key key = new Key(); try { key = Key.parseFrom(byteStream.toByteArray()); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key checksum failed"); System.exit(1); } proto = key; proto = decodeKey(payload, fromLogs); } else { // other types are wrapped in a checksum message CheckedMessage wrapper = new CheckedMessage(); try { MessageNano.mergeFrom(wrapper, byteStream.toByteArray()); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse wrapper: " + e); System.exit(1); } CRC32 checksum = new CRC32(); checksum.update(wrapper.payload); if (wrapper.checksum != checksum.getValue()) { System.err.println("wrapper checksum failed"); System.exit(1); } // decode the actual message proto = (MessageNano) type.newInstance(); try { MessageNano.mergeFrom(proto, wrapper.payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } proto = decodeBackupData(payload, type, fromLogs); } // Generic string output Loading Loading @@ -245,11 +215,75 @@ class DecoderRing { } } } // success } System.exit(0); } // In logcat, backup data is base64 encoded, but in localtransport files it is raw private static MessageNano decodeBackupData(byte[] payload, Class type, boolean fromLogs) throws InstantiationException, IllegalAccessException { MessageNano proto;// other types are wrapped in a checksum message CheckedMessage wrapper = new CheckedMessage(); try { if (fromLogs) { payload = DatatypeConverter.parseBase64Binary(new String(payload)); } MessageNano.mergeFrom(wrapper, payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse wrapper: " + e); System.exit(1); } CRC32 checksum = new CRC32(); checksum.update(wrapper.payload); if (wrapper.checksum != checksum.getValue()) { System.err.println("wrapper checksum failed"); System.exit(1); } // decode the actual message proto = (MessageNano) type.newInstance(); try { MessageNano.mergeFrom(proto, wrapper.payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } return proto; } // In logcat, keys are base64 encoded with no prefix. // The localtransport adds a prefix and the base64 encodes the whole thing again. private static Key decodeKey(byte[] payload, boolean fromLogs) { Key key = new Key(); try { String encodedKey = new String(payload); if (!fromLogs) { byte[] rawKey = DatatypeConverter.parseBase64Binary(encodedKey); if (rawKey[0] != 'L' || rawKey[1] != ':') { System.err.println(encodedKey + " is not a launcher backup key."); System.exit(1); } encodedKey = new String(rawKey, 2, rawKey.length - 2); } byte[] keyProtoData = DatatypeConverter.parseBase64Binary(encodedKey); key = Key.parseFrom(keyProtoData); } catch (InvalidProtocolBufferNanoException protoException) { System.err.println("failed to extract key from filename: " + protoException); System.exit(1); } catch (IllegalArgumentException base64Exception) { System.err.println("failed to extract key from filename: " + base64Exception); System.exit(1); } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key ckecksum failed"); System.exit(1); } return key; } private static void writeImageData(byte[] data, String path) { FileOutputStream iconFile = null; try { Loading Loading @@ -289,6 +323,7 @@ class DecoderRing { System.err.println("\t-w\tdecode a widget"); System.err.println("\t-S b\tskip b bytes"); System.err.println("\t-x\textract image data to files"); System.err.println("\t-l\texpect data from logcat, instead of the local transport"); System.err.println("\tfilename\tread from filename, not stdin"); System.exit(1); } Loading Loading
util/com/android/launcher3/DecoderRing.java +167 −132 Original line number Diff line number Diff line Loading @@ -15,7 +15,6 @@ */ package com.android.launcher3; import com.android.launcher3.backup.BackupProtos; import com.android.launcher3.backup.BackupProtos.CheckedMessage; import com.android.launcher3.backup.BackupProtos.Favorite; import com.android.launcher3.backup.BackupProtos.Key; Loading @@ -35,6 +34,8 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.System; import java.util.LinkedList; import java.util.List; import java.util.zip.CRC32; import javax.xml.bind.DatatypeConverter; Loading @@ -46,7 +47,7 @@ import javax.xml.bind.DatatypeConverter; * <P>When using com.android.internal.backup.LocalTransport, the file names are base64-encoded Key * protocol buffers with a prefix, that have been base64-encoded again by the transport: * <pre> * echo TDpDQUlnL0pxVTVnOD0= | base64 -D | dd bs=1 skip=2 | base64 -D | launcher_protoutil -k * echo "TDpDQUlnL0pxVTVnOD0=" | launcher_protoutil -k * </pre> * * <P>This tool understands these file names and will use the embedded Key to detect the type and Loading @@ -56,13 +57,19 @@ import javax.xml.bind.DatatypeConverter; * </pre> * * <P>With payload debugging enabled, base64-encoded protocol buffers will be written to the logs. * Copy the encoded log snippet into a file, and specify the type explicitly: * Copy the encoded snippet from the log, and specify the type explicitly, with the Logs flags: * <pre> * base64 -D icon.log > icon.bin * launcher_protoutil -i icon.bin * echo "CAEYLiCJ9JKsDw==" | launcher_protoutil -L -k * </pre> * For backup payloads it is more convenient to copy the log snippet to a file: * <pre> * launcher_protoutil -L -f favorite.log * </pre> */ class DecoderRing { public static final String STANDARD_IN = "**stdin**"; private static Class[] TYPES = { Key.class, Favorite.class, Loading @@ -74,24 +81,25 @@ class DecoderRing { public static void main(String[ ] args) throws Exception { File source = null; Class type = null; Class defaultType = null; boolean extractImages = false; boolean fromLogs = false; int skip = 0; List<File> files = new LinkedList<File>(); for (int i = 0; i < args.length; i++) { if ("-k".equals(args[i])) { type = Key.class; defaultType = Key.class; } else if ("-f".equals(args[i])) { type = Favorite.class; defaultType = Favorite.class; } else if ("-j".equals(args[i])) { type = Journal.class; defaultType = Journal.class; } else if ("-i".equals(args[i])) { type = Resource.class; defaultType = Resource.class; } else if ("-s".equals(args[i])) { type = Screen.class; defaultType = Screen.class; } else if ("-w".equals(args[i])) { type = Widget.class; defaultType = Widget.class; } else if ("-S".equals(args[i])) { if ((i + 1) < args.length) { skip = Integer.valueOf(args[++i]); Loading @@ -100,50 +108,44 @@ class DecoderRing { } } else if ("-x".equals(args[i])) { extractImages = true; } else if ("-L".equals(args[i])) { fromLogs = true; } else if (args[i] != null && !args[i].startsWith("-")) { source = new File(args[i]); files.add(new File(args[i])); } else { System.err.println("Unsupported flag: " + args[i]); usage(args); } } if (type == null) { if (source == null) { if (defaultType == null && files.isEmpty()) { // can't infer file type without the key usage(args); } else { Key key = new Key(); try { byte[] rawKey = DatatypeConverter.parseBase64Binary(source.getName()); if (rawKey[0] != 'L' || rawKey[1] != ':') { System.err.println("you must specify the payload type. " + source.getName() + " is not a launcher backup key."); System.exit(1); } String encodedPayload = new String(rawKey, 2, rawKey.length - 2); byte[] keyProtoData = DatatypeConverter.parseBase64Binary(encodedPayload); key = Key.parseFrom(keyProtoData); } catch (InvalidProtocolBufferNanoException protoException) { System.err.println("failed to extract key from filename: " + protoException); System.exit(1); } catch (IllegalArgumentException base64Exception) { System.err.println("failed to extract key from filename: " + base64Exception); System.exit(1); if (files.size() > 1) { System.err.println("Explicit type ignored for multiple files."); defaultType = null; } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key ckecksum failed"); System.exit(1); if (files.isEmpty()) { files.add(new File(STANDARD_IN)); } for (File source : files) { Class type = null; if (defaultType == null) { Key key = decodeKey(source.getName().getBytes(), fromLogs); type = TYPES[key.type]; System.err.println("This is a " + type.getSimpleName() + " backup"); } } else { type = defaultType; } // read in the bytes ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); BufferedInputStream input = null; if (source == null) { if (source.getName() == STANDARD_IN) { input = new BufferedInputStream(System.in); } else { try { Loading Loading @@ -173,43 +175,11 @@ class DecoderRing { } MessageNano proto = null; byte[] payload = byteStream.toByteArray(); if (type == Key.class) { Key key = new Key(); try { key = Key.parseFrom(byteStream.toByteArray()); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key checksum failed"); System.exit(1); } proto = key; proto = decodeKey(payload, fromLogs); } else { // other types are wrapped in a checksum message CheckedMessage wrapper = new CheckedMessage(); try { MessageNano.mergeFrom(wrapper, byteStream.toByteArray()); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse wrapper: " + e); System.exit(1); } CRC32 checksum = new CRC32(); checksum.update(wrapper.payload); if (wrapper.checksum != checksum.getValue()) { System.err.println("wrapper checksum failed"); System.exit(1); } // decode the actual message proto = (MessageNano) type.newInstance(); try { MessageNano.mergeFrom(proto, wrapper.payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } proto = decodeBackupData(payload, type, fromLogs); } // Generic string output Loading Loading @@ -245,11 +215,75 @@ class DecoderRing { } } } // success } System.exit(0); } // In logcat, backup data is base64 encoded, but in localtransport files it is raw private static MessageNano decodeBackupData(byte[] payload, Class type, boolean fromLogs) throws InstantiationException, IllegalAccessException { MessageNano proto;// other types are wrapped in a checksum message CheckedMessage wrapper = new CheckedMessage(); try { if (fromLogs) { payload = DatatypeConverter.parseBase64Binary(new String(payload)); } MessageNano.mergeFrom(wrapper, payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse wrapper: " + e); System.exit(1); } CRC32 checksum = new CRC32(); checksum.update(wrapper.payload); if (wrapper.checksum != checksum.getValue()) { System.err.println("wrapper checksum failed"); System.exit(1); } // decode the actual message proto = (MessageNano) type.newInstance(); try { MessageNano.mergeFrom(proto, wrapper.payload); } catch (InvalidProtocolBufferNanoException e) { System.err.println("failed to parse proto: " + e); System.exit(1); } return proto; } // In logcat, keys are base64 encoded with no prefix. // The localtransport adds a prefix and the base64 encodes the whole thing again. private static Key decodeKey(byte[] payload, boolean fromLogs) { Key key = new Key(); try { String encodedKey = new String(payload); if (!fromLogs) { byte[] rawKey = DatatypeConverter.parseBase64Binary(encodedKey); if (rawKey[0] != 'L' || rawKey[1] != ':') { System.err.println(encodedKey + " is not a launcher backup key."); System.exit(1); } encodedKey = new String(rawKey, 2, rawKey.length - 2); } byte[] keyProtoData = DatatypeConverter.parseBase64Binary(encodedKey); key = Key.parseFrom(keyProtoData); } catch (InvalidProtocolBufferNanoException protoException) { System.err.println("failed to extract key from filename: " + protoException); System.exit(1); } catch (IllegalArgumentException base64Exception) { System.err.println("failed to extract key from filename: " + base64Exception); System.exit(1); } // keys are self-checked if (key.checksum != checkKey(key)) { System.err.println("key ckecksum failed"); System.exit(1); } return key; } private static void writeImageData(byte[] data, String path) { FileOutputStream iconFile = null; try { Loading Loading @@ -289,6 +323,7 @@ class DecoderRing { System.err.println("\t-w\tdecode a widget"); System.err.println("\t-S b\tskip b bytes"); System.err.println("\t-x\textract image data to files"); System.err.println("\t-l\texpect data from logcat, instead of the local transport"); System.err.println("\tfilename\tread from filename, not stdin"); System.exit(1); } Loading