From 2b6c21d434b647fbba48fb61bf7ae3a66af35e9a Mon Sep 17 00:00:00 2001 From: Chris Wren Date: Wed, 2 Oct 2013 14:16:04 -0400 Subject: [PATCH] add a proto decoder host utility Bug: 10778984 Change-Id: I1c0203a3a5b3a3b1e565af387ccdfa92b53f8335 --- Android.mk | 26 ++- .../launcher3/LauncherBackupAgent.java | 11 +- util/com/android/launcher3/DecoderRing.java | 196 ++++++++++++++++++ 3 files changed, 228 insertions(+), 5 deletions(-) create mode 100644 util/com/android/launcher3/DecoderRing.java diff --git a/Android.mk b/Android.mk index 10c9f24477..e22d53cf60 100644 --- a/Android.mk +++ b/Android.mk @@ -15,18 +15,22 @@ # LOCAL_PATH := $(call my-dir) + +# +# Build app code. +# include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_STATIC_JAVA_LIBRARIES := android-support-v13 -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) \ +LOCAL_SRC_FILES := $(call all-java-files-under, src) \ + $(call all-renderscript-files-under, src) \ $(call all-proto-files-under, protos) LOCAL_PROTOC_OPTIMIZE_TYPE := nano - -LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos +LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ LOCAL_SDK_VERSION := 17 @@ -40,3 +44,19 @@ LOCAL_PROGUARD_FLAG_FILES := proguard.flags include $(BUILD_PACKAGE) include $(call all-makefiles-under,$(LOCAL_PATH)) + +# +# Protocol Buffer Debug Utility in Java +# +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under, util) \ + $(call all-proto-files-under, protos) + +LOCAL_PROTOC_OPTIMIZE_TYPE := nano +LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/protos/ + +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE := protoutil + +include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java index 95c1b843f3..7cffe7bc67 100644 --- a/src/com/android/launcher3/LauncherBackupAgent.java +++ b/src/com/android/launcher3/LauncherBackupAgent.java @@ -892,8 +892,15 @@ public class LauncherBackupAgent extends BackupAgent { out.bytes += blob.length; Log.v(TAG, "saving " + geKeyType(key) + " " + backupKey + ": " + getKeyName(key) + "/" + blob.length); - if(DEBUG) Log.d(TAG, "wrote " + - Base64.encodeToString(blob, 0, blob.length, Base64.NO_WRAP)); + if(DEBUG) { + String encoded = Base64.encodeToString(blob, 0, blob.length, Base64.NO_WRAP); + final int chunkSize = 1024; + for (int offset = 0; offset < encoded.length(); offset += chunkSize) { + int end = offset + chunkSize; + end = Math.min(end, encoded.length()); + Log.d(TAG, "wrote " + encoded.substring(offset, end)); + } + } } private Set getSavedIdsByType(int type, Journal in) { diff --git a/util/com/android/launcher3/DecoderRing.java b/util/com/android/launcher3/DecoderRing.java new file mode 100644 index 0000000000..cde845e334 --- /dev/null +++ b/util/com/android/launcher3/DecoderRing.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2013 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. + */ +package com.android.launcher3; + +import com.android.launcher3.backup.BackupProtos.CheckedMessage; +import com.android.launcher3.backup.BackupProtos.Favorite; +import com.android.launcher3.backup.BackupProtos.Key; +import com.android.launcher3.backup.BackupProtos.Resource; +import com.android.launcher3.backup.BackupProtos.Screen; +import com.android.launcher3.backup.BackupProtos.Widget; + +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; +import com.google.protobuf.nano.MessageNano; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.lang.System; +import java.util.zip.CRC32; + +/** + * Commandline utility for decoding protos written to the android logs during debugging. + * + * base64 -D icon.log > icon.bin + * java -classpath $ANDROID_HOST_OUT/framework/protoutil.jar:$ANDROID_HOST_OUT/../common/obj/JAVA_LIBRARIES/host-libprotobuf-java-2.3.0-nano_intermediates/javalib.jar \ + * com.android.launcher3.DecoderRing -i icon.bin + * + * TODO: write a wrapper to setup the classpath + */ +class DecoderRing { + public static void main(String[ ] args) + throws Exception { + File source = null; + Class type = Key.class; + for (int i = 0; i < args.length; i++) { + if ("-k".equals(args[i])) { + type = Key.class; + } else if ("-f".equals(args[i])) { + type = Favorite.class; + } else if ("-i".equals(args[i])) { + type = Resource.class; + } else if ("-s".equals(args[i])) { + type = Screen.class; + } else if ("-w".equals(args[i])) { + type = Widget.class; + } else if (args[i] != null && !args[i].startsWith("-")) { + source = new File(args[i]); + } else { + System.err.println("Unsupported flag: " + args[i]); + usage(args); + } + } + + + // read in the bytes + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + BufferedInputStream input = null; + if (source == null) { + input = new BufferedInputStream(System.in); + } else { + try { + input = new BufferedInputStream(new FileInputStream(source)); + } catch (FileNotFoundException e) { + System.err.println("failed to open file: " + source + ", " + e); + System.exit(1); + } + } + byte[] buffer = new byte[1024]; + try { + while (input.available() > 0) { + int n = input.read(buffer); + if (n > 0) { + byteStream.write(buffer, 0, n); + } + } + } catch (IOException e) { + System.err.println("failed to read input: " + e); + System.exit(1); + } + System.err.println("read this many bytes: " + byteStream.size()); + + MessageNano proto = null; + if (type == Key.class) { + Key key = new Key(); + try { + MessageNano.mergeFrom(key, 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 ckecksum failed"); + System.exit(1); + } + proto = key; + } 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 ckecksum 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); + } + } + + // Generic string output + System.out.println(proto.toString()); + + // save off the icon bits in a file for inspection + if (proto instanceof Resource) { + Resource icon = (Resource) proto; + final String path = "icon.webp"; + FileOutputStream iconFile = new FileOutputStream(path); + iconFile.write(icon.data); + iconFile.close(); + System.err.println("wrote " + path); + } + + // save off the widget icon and preview bits in files for inspection + if (proto instanceof Widget) { + Widget widget = (Widget) proto; + if (widget.icon != null) { + final String path = "widget_icon.webp"; + FileOutputStream iconFile = new FileOutputStream(path); + iconFile.write(widget.icon.data); + iconFile.close(); + System.err.println("wrote " + path); + } + if (widget.preview != null) { + final String path = "widget_preview.webp"; + FileOutputStream iconFile = new FileOutputStream(path); + iconFile.write(widget.preview.data); + iconFile.close(); + System.err.println("wrote " + path); + } + } + + // success + System.exit(0); + } + + private static long checkKey(Key key) { + CRC32 checksum = new CRC32(); + checksum.update(key.type); + checksum.update((int) (key.id & 0xffff)); + checksum.update((int) ((key.id >> 32) & 0xffff)); + if (key.name != null && key.name.length() > 0) { + checksum.update(key.name.getBytes()); + } + return checksum.getValue(); + } + + private static void usage(String[] args) { + System.err.println("DecoderRing type [input]"); + System.err.println("\t-k\tdecode a key"); + System.err.println("\t-f\tdecode a favorite"); + System.err.println("\t-i\tdecode a icon"); + System.err.println("\t-s\tdecode a screen"); + System.err.println("\t-w\tdecode a widget"); + System.err.println("\tfilename\tread from filename, not stdin"); + System.exit(1); + } +} \ No newline at end of file