ASN1Type.java revision 897538a36c18f4db8f9f68ee566aec0bda842e9f
1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* 2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Licensed to the Apache Software Foundation (ASF) under one or more 3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements. See the NOTICE file distributed with 4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership. 5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0 6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with 7adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License. You may obtain a copy of the License at 8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 9adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and 15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License. 16adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @author Vladimir N. Molotkov, Stepan M. Mishura 20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project* @version $Revision$ 21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project*/ 22adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpackage org.apache.harmony.security.asn1; 24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException; 26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.InputStream; 27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/** 30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * This abstract class is the super class for all ASN.1 types 31f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @see <a href="http://asn1.elibel.tm.fr/en/standards/index.htm">ASN.1</a> 33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectpublic abstract class ASN1Type implements ASN1Constants { 36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 37adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 38adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Integer representation of primitive identifier. 39adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 40adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int id; 41adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 42adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 43adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Integer representation of constructed identifier. 44adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final int constrId; 46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs a primitive, universal ASN.1 type. 49f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param tagNumber - ASN.1 tag number 51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalArgumentException - if tagNumber is invalid 52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public ASN1Type(int tagNumber) { 54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this(CLASS_UNIVERSAL, tagNumber); 55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 56adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 58adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Constructs an ASN.1 type. 59f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param tagClass - tag class. MUST be 61adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * CLASS_UNIVERSAL, CLASS_APPLICATION, CLASS_CONTEXTSPECIFIC, CLASS_PRIVATE 62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param isConstructed - is ASN.1 type is a constructed type. 63adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param tagNumber - ASN.1 tag number. 64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IllegalArgumentException - if tagClass or tagNumber is invalid 65adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public ASN1Type(int tagClass, int tagNumber) { 67adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tagNumber < 0) { 68897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new IllegalArgumentException("tagNumber < 0"); 69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 70adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tagClass != CLASS_UNIVERSAL && tagClass != CLASS_APPLICATION 72adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project && tagClass != CLASS_CONTEXTSPECIFIC 73adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project && tagClass != CLASS_PRIVATE) { 74897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new IllegalArgumentException("invalid tagClass"); 75adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 76adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 77adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (tagNumber < 31) { 78adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // short form 79adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.id = tagClass + tagNumber; 80adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } else { 81adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // long form 82897538a36c18f4db8f9f68ee566aec0bda842e9fElliott Hughes throw new IllegalArgumentException("tag long form not implemented"); 83adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project this.constrId = this.id + PC_CONSTRUCTED; 85adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 86adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 88adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Stubs for DER 90adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 91adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 92adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 93adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final Object decode(byte[] encoded) throws IOException { 94adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return decode(new DerInputStream(encoded)); 95adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 96adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 97adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final Object decode(byte[] encoded, int offset, int encodingLen) 98adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project throws IOException { 99adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return decode(new DerInputStream(encoded, offset, encodingLen)); 100adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final Object decode(InputStream in) throws IOException { 103adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return decode(new DerInputStream(in)); 104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 105adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final void verify(byte[] encoded) throws IOException { 107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project DerInputStream decoder = new DerInputStream(encoded); 108adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decoder.setVerify(); 109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decode(decoder); 110adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 111adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 112adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final void verify(InputStream in) throws IOException { 113adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project DerInputStream decoder = new DerInputStream(in); 114adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decoder.setVerify(); 115adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project decode(decoder); 116adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public final byte[] encode(Object object) { 119adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project DerOutputStream out = new DerOutputStream(this, object); 121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return out.encoded; 122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Decode 127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 130adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Decodes ASN.1 type. 132f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param in - 134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * BER input stream 135adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @throws IOException - 136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * if an I/O error occurs or the end of the stream is reached 137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract Object decode(BerInputStream in) throws IOException; 139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 140adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Tests provided identifier. 142f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param identifier - 144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * identifier to be verified 145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return - true if identifier is associated with this ASN.1 type, 146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * otherwise false 147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract boolean checkTag(int identifier); 149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 151adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Creates decoded object. 152f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 153adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Derived classes should override this method to provide creation for a 154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * selected class of objects during decoding. 155f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 156adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The default implementation returns an object created by decoding stream. 157f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes * 158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param - 159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * input stream 160adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @return - created object 161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project //FIXME make me public 163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project protected Object getDecodedObject(BerInputStream in) throws IOException { 164adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return in.content; 165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 169adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // Encode 170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 171adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // 172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project /** 174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Encodes ASN.1 type. 175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * 176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * @param out - BER output stream 177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */ 178adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract void encodeASN(BerOutputStream out); 179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 180adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract void encodeContent(BerOutputStream out); 181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public abstract void setEncodingContent(BerOutputStream out); 183adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 184adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public int getEncodedLength(BerOutputStream out) { //FIXME name 185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project //tag length 187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project int len = 1; //FIXME tag length = 1. what about long form? 188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project //for (; tag > 0; tag = tag >> 8, len++); 189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // length length :-) 191adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project len++; 192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project if (out.length > 127) { 193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project len++; 195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project for (int cur = out.length >> 8; cur > 0; len++) { 196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project cur = cur >> 8; 197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project len += out.length; 200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project return len; 202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project 204adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project public String toString() { 205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project // TODO decide whether this method is necessary 206adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project //FIXME fix performance 207f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes return this.getClass().getName() + "(tag: 0x" 208f33eae7e84eb6d3b0f4e86b59605bb3de73009f3Elliott Hughes + Integer.toHexString(0xff & this.id) + ")"; 209adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project } 210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project} 211