blob: 1d9e0defb16452fd035fd40adf6e3ae73942506c [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;
52 Class type = Key.class;
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
82
83 // read in the bytes
84 ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
85 BufferedInputStream input = null;
86 if (source == null) {
87 input = new BufferedInputStream(System.in);
88 } else {
89 try {
90 input = new BufferedInputStream(new FileInputStream(source));
91 } catch (FileNotFoundException e) {
92 System.err.println("failed to open file: " + source + ", " + e);
93 System.exit(1);
94 }
95 }
96 byte[] buffer = new byte[1024];
97 try {
98 while (input.available() > 0) {
99 int n = input.read(buffer);
Chris Wren92aa4232013-10-04 11:29:36 -0400100 int offset = 0;
101 if (skip > 0) {
102 offset = Math.min(skip, n);
103 n -= offset;
104 skip -= offset;
105 }
Chris Wren2b6c21d2013-10-02 14:16:04 -0400106 if (n > 0) {
Chris Wren92aa4232013-10-04 11:29:36 -0400107 byteStream.write(buffer, offset, n);
Chris Wren2b6c21d2013-10-02 14:16:04 -0400108 }
109 }
110 } catch (IOException e) {
111 System.err.println("failed to read input: " + e);
112 System.exit(1);
113 }
114 System.err.println("read this many bytes: " + byteStream.size());
115
116 MessageNano proto = null;
117 if (type == Key.class) {
118 Key key = new Key();
119 try {
Chris Wren978194c2013-10-03 17:47:22 -0400120 key = Key.parseFrom(byteStream.toByteArray());
Chris Wren2b6c21d2013-10-02 14:16:04 -0400121 } catch (InvalidProtocolBufferNanoException e) {
122 System.err.println("failed to parse proto: " + e);
123 System.exit(1);
124 }
125 // keys are self-checked
126 if (key.checksum != checkKey(key)) {
127 System.err.println("key ckecksum failed");
128 System.exit(1);
129 }
130 proto = key;
131 } else {
132 // other types are wrapped in a checksum message
133 CheckedMessage wrapper = new CheckedMessage();
134 try {
135 MessageNano.mergeFrom(wrapper, byteStream.toByteArray());
136 } catch (InvalidProtocolBufferNanoException e) {
137 System.err.println("failed to parse wrapper: " + e);
138 System.exit(1);
139 }
140 CRC32 checksum = new CRC32();
141 checksum.update(wrapper.payload);
142 if (wrapper.checksum != checksum.getValue()) {
143 System.err.println("wrapper ckecksum failed");
144 System.exit(1);
145 }
146 // decode the actual message
147 proto = (MessageNano) type.newInstance();
148 try {
149 MessageNano.mergeFrom(proto, wrapper.payload);
150 } catch (InvalidProtocolBufferNanoException e) {
151 System.err.println("failed to parse proto: " + e);
152 System.exit(1);
153 }
154 }
155
156 // Generic string output
157 System.out.println(proto.toString());
158
159 // save off the icon bits in a file for inspection
160 if (proto instanceof Resource) {
161 Resource icon = (Resource) proto;
162 final String path = "icon.webp";
163 FileOutputStream iconFile = new FileOutputStream(path);
164 iconFile.write(icon.data);
165 iconFile.close();
166 System.err.println("wrote " + path);
167 }
168
169 // save off the widget icon and preview bits in files for inspection
170 if (proto instanceof Widget) {
171 Widget widget = (Widget) proto;
172 if (widget.icon != null) {
173 final String path = "widget_icon.webp";
174 FileOutputStream iconFile = new FileOutputStream(path);
175 iconFile.write(widget.icon.data);
176 iconFile.close();
177 System.err.println("wrote " + path);
178 }
179 if (widget.preview != null) {
180 final String path = "widget_preview.webp";
181 FileOutputStream iconFile = new FileOutputStream(path);
182 iconFile.write(widget.preview.data);
183 iconFile.close();
184 System.err.println("wrote " + path);
185 }
186 }
187
188 // success
189 System.exit(0);
190 }
191
192 private static long checkKey(Key key) {
193 CRC32 checksum = new CRC32();
194 checksum.update(key.type);
195 checksum.update((int) (key.id & 0xffff));
196 checksum.update((int) ((key.id >> 32) & 0xffff));
197 if (key.name != null && key.name.length() > 0) {
198 checksum.update(key.name.getBytes());
199 }
200 return checksum.getValue();
201 }
202
203 private static void usage(String[] args) {
204 System.err.println("DecoderRing type [input]");
205 System.err.println("\t-k\tdecode a key");
206 System.err.println("\t-f\tdecode a favorite");
207 System.err.println("\t-i\tdecode a icon");
208 System.err.println("\t-s\tdecode a screen");
209 System.err.println("\t-w\tdecode a widget");
Chris Wren92aa4232013-10-04 11:29:36 -0400210 System.err.println("\t-s b\tskip b bytes");
Chris Wren2b6c21d2013-10-02 14:16:04 -0400211 System.err.println("\tfilename\tread from filename, not stdin");
212 System.exit(1);
213 }
214}