blob: bd0275e5faf800b2d3711be29ac3818c8745e5f5 [file] [log] [blame]
Chris Wren2b6c21d2013-10-02 14:16:04 -04001/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.launcher3;
17
18import com.android.launcher3.backup.BackupProtos.CheckedMessage;
19import com.android.launcher3.backup.BackupProtos.Favorite;
20import com.android.launcher3.backup.BackupProtos.Key;
Chris Wren92aa4232013-10-04 11:29:36 -040021import com.android.launcher3.backup.BackupProtos.Journal;
Chris Wren2b6c21d2013-10-02 14:16:04 -040022import com.android.launcher3.backup.BackupProtos.Resource;
23import com.android.launcher3.backup.BackupProtos.Screen;
24import com.android.launcher3.backup.BackupProtos.Widget;
25
26import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
27import com.google.protobuf.nano.MessageNano;
28
29import java.io.BufferedInputStream;
30import java.io.ByteArrayOutputStream;
31import java.io.File;
32import java.io.FileInputStream;
33import java.io.FileNotFoundException;
34import java.io.FileOutputStream;
35import java.io.IOException;
36import java.lang.System;
37import java.util.zip.CRC32;
38
39/**
40 * Commandline utility for decoding protos written to the android logs during debugging.
41 *
42 * base64 -D icon.log > icon.bin
43 * 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 \
44 * com.android.launcher3.DecoderRing -i icon.bin
45 *
46 * TODO: write a wrapper to setup the classpath
47 */
48class DecoderRing {
49 public static void main(String[ ] args)
50 throws Exception {
51 File source = null;
Chris Wrenba2923a2013-12-10 15:48:47 -050052 Class type = null;
Chris Wren92aa4232013-10-04 11:29:36 -040053 int skip = 0;
54
Chris Wren2b6c21d2013-10-02 14:16:04 -040055 for (int i = 0; i < args.length; i++) {
56 if ("-k".equals(args[i])) {
57 type = Key.class;
58 } else if ("-f".equals(args[i])) {
59 type = Favorite.class;
Chris Wren92aa4232013-10-04 11:29:36 -040060 } else if ("-j".equals(args[i])) {
61 type = Journal.class;
Chris Wren2b6c21d2013-10-02 14:16:04 -040062 } else if ("-i".equals(args[i])) {
63 type = Resource.class;
64 } else if ("-s".equals(args[i])) {
65 type = Screen.class;
66 } else if ("-w".equals(args[i])) {
67 type = Widget.class;
Chris Wren92aa4232013-10-04 11:29:36 -040068 } else if ("-S".equals(args[i])) {
69 if ((i + 1) < args.length) {
70 skip = Integer.valueOf(args[++i]);
71 } else {
72 usage(args);
73 }
Chris Wren2b6c21d2013-10-02 14:16:04 -040074 } else if (args[i] != null && !args[i].startsWith("-")) {
75 source = new File(args[i]);
76 } else {
77 System.err.println("Unsupported flag: " + args[i]);
78 usage(args);
79 }
80 }
81
Chris Wrenba2923a2013-12-10 15:48:47 -050082 if (type == null) {
83 usage(args);
84 }
Chris Wren2b6c21d2013-10-02 14:16:04 -040085
86 // read in the bytes
87 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
88 BufferedInputStream input = null;
89 if (source == null) {
90 input = new BufferedInputStream(System.in);
91 } else {
92 try {
93 input = new BufferedInputStream(new FileInputStream(source));
94 } catch (FileNotFoundException e) {
95 System.err.println("failed to open file: " + source + ", " + e);
96 System.exit(1);
97 }
98 }
99 byte[] buffer = new byte[1024];
100 try {
101 while (input.available() > 0) {
102 int n = input.read(buffer);
Chris Wren92aa4232013-10-04 11:29:36 -0400103 int offset = 0;
104 if (skip > 0) {
105 offset = Math.min(skip, n);
106 n -= offset;
107 skip -= offset;
108 }
Chris Wren2b6c21d2013-10-02 14:16:04 -0400109 if (n > 0) {
Chris Wren92aa4232013-10-04 11:29:36 -0400110 byteStream.write(buffer, offset, n);
Chris Wren2b6c21d2013-10-02 14:16:04 -0400111 }
112 }
113 } catch (IOException e) {
114 System.err.println("failed to read input: " + e);
115 System.exit(1);
116 }
117 System.err.println("read this many bytes: " + byteStream.size());
118
119 MessageNano proto = null;
120 if (type == Key.class) {
121 Key key = new Key();
122 try {
Chris Wren978194c2013-10-03 17:47:22 -0400123 key = Key.parseFrom(byteStream.toByteArray());
Chris Wren2b6c21d2013-10-02 14:16:04 -0400124 } catch (InvalidProtocolBufferNanoException e) {
125 System.err.println("failed to parse proto: " + e);
126 System.exit(1);
127 }
128 // keys are self-checked
129 if (key.checksum != checkKey(key)) {
130 System.err.println("key ckecksum failed");
131 System.exit(1);
132 }
133 proto = key;
134 } else {
135 // other types are wrapped in a checksum message
136 CheckedMessage wrapper = new CheckedMessage();
137 try {
138 MessageNano.mergeFrom(wrapper, byteStream.toByteArray());
139 } catch (InvalidProtocolBufferNanoException e) {
140 System.err.println("failed to parse wrapper: " + e);
141 System.exit(1);
142 }
143 CRC32 checksum = new CRC32();
144 checksum.update(wrapper.payload);
145 if (wrapper.checksum != checksum.getValue()) {
146 System.err.println("wrapper ckecksum failed");
147 System.exit(1);
148 }
149 // decode the actual message
150 proto = (MessageNano) type.newInstance();
151 try {
152 MessageNano.mergeFrom(proto, wrapper.payload);
153 } catch (InvalidProtocolBufferNanoException e) {
154 System.err.println("failed to parse proto: " + e);
155 System.exit(1);
156 }
157 }
158
159 // Generic string output
160 System.out.println(proto.toString());
161
162 // save off the icon bits in a file for inspection
163 if (proto instanceof Resource) {
164 Resource icon = (Resource) proto;
165 final String path = "icon.webp";
166 FileOutputStream iconFile = new FileOutputStream(path);
167 iconFile.write(icon.data);
168 iconFile.close();
169 System.err.println("wrote " + path);
170 }
171
172 // save off the widget icon and preview bits in files for inspection
173 if (proto instanceof Widget) {
174 Widget widget = (Widget) proto;
175 if (widget.icon != null) {
176 final String path = "widget_icon.webp";
177 FileOutputStream iconFile = new FileOutputStream(path);
178 iconFile.write(widget.icon.data);
179 iconFile.close();
180 System.err.println("wrote " + path);
181 }
182 if (widget.preview != null) {
183 final String path = "widget_preview.webp";
184 FileOutputStream iconFile = new FileOutputStream(path);
185 iconFile.write(widget.preview.data);
186 iconFile.close();
187 System.err.println("wrote " + path);
188 }
189 }
190
191 // success
192 System.exit(0);
193 }
194
195 private static long checkKey(Key key) {
196 CRC32 checksum = new CRC32();
197 checksum.update(key.type);
198 checksum.update((int) (key.id & 0xffff));
199 checksum.update((int) ((key.id >> 32) & 0xffff));
200 if (key.name != null && key.name.length() > 0) {
201 checksum.update(key.name.getBytes());
202 }
203 return checksum.getValue();
204 }
205
206 private static void usage(String[] args) {
207 System.err.println("DecoderRing type [input]");
208 System.err.println("\t-k\tdecode a key");
209 System.err.println("\t-f\tdecode a favorite");
210 System.err.println("\t-i\tdecode a icon");
211 System.err.println("\t-s\tdecode a screen");
212 System.err.println("\t-w\tdecode a widget");
Chris Wren92aa4232013-10-04 11:29:36 -0400213 System.err.println("\t-s b\tskip b bytes");
Chris Wren2b6c21d2013-10-02 14:16:04 -0400214 System.err.println("\tfilename\tread from filename, not stdin");
215 System.exit(1);
216 }
217}