1/* 2 * Copyright (C) 2008 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 */ 16 17package android.tests.sigtest; 18 19import android.app.Activity; 20import android.content.Intent; 21import android.content.res.Resources; 22import android.content.res.Resources.NotFoundException; 23import android.os.Bundle; 24 25import org.xmlpull.v1.XmlPullParserException; 26 27import java.io.BufferedReader; 28import java.io.IOException; 29import java.io.InputStream; 30import java.io.InputStreamReader; 31import java.lang.reflect.Field; 32import java.util.ArrayList; 33import java.util.HashMap; 34import java.util.HashSet; 35 36/** 37 * This class is used for Signature Test. It will started by the Instrumentation class, 38 * and send back the test result via IBinder. 39 */ 40public class SignatureTestActivity extends Activity { 41 static final String BUNDLE_EXTRA_SIG_TEST = "sigtest"; 42 43 static final String BUNDLE_KEY_RESULT = "result"; 44 static final String BUNDLE_KEY_MISSING_CLASS = "missing_class"; 45 static final String BUNDLE_KEY_MISSING_INTERFACE = "missing_interface"; 46 static final String BUNDLE_KEY_MISSING_METHOD = "missing_method"; 47 static final String BUNDLE_KEY_MISSING_FIELD = "missing_field"; 48 static final String BUNDLE_KEY_MISMATCH_CLASS = "mismatch_class_signature"; 49 static final String BUNDLE_KEY_MISMATCH_INTERFACE = "mismatch_interface_signature"; 50 static final String BUNDLE_KEY_MISMATCH_METHOD = "mismatch_method_signature"; 51 static final String BUNDLE_KEY_MISMATCH_FIELD = "mismatch_field_signature"; 52 static final String BUNDLE_KEY_CAUGHT_EXCEPTION = "caught_exception"; 53 54 55 static final int GET_SIG_TEST_RESULT_TRANSACTION = 101; 56 57 private DeviceResultObserver mResultObserver; 58 59 /** 60 * Define the type of the signature check failures. 61 */ 62 public static enum FAILURE_TYPE { 63 MISSING_CLASS, 64 MISSING_INTERFACE, 65 MISSING_METHOD, 66 MISSING_FIELD, 67 MISMATCH_CLASS, 68 MISMATCH_INTERFACE, 69 MISMATCH_METHOD, 70 MISMATCH_FIELD, 71 CAUGHT_EXCEPTION, 72 } 73 74 static final HashMap<FAILURE_TYPE, String> FAILURE_TYPE_TO_KEY = 75 new HashMap<FAILURE_TYPE, String>(); 76 static { 77 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_CLASS, BUNDLE_KEY_MISSING_CLASS); 78 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_INTERFACE, BUNDLE_KEY_MISSING_INTERFACE); 79 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_METHOD, BUNDLE_KEY_MISSING_METHOD); 80 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISSING_FIELD, BUNDLE_KEY_MISSING_FIELD); 81 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_CLASS, BUNDLE_KEY_MISMATCH_CLASS); 82 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_INTERFACE, BUNDLE_KEY_MISMATCH_INTERFACE); 83 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_METHOD, BUNDLE_KEY_MISMATCH_METHOD); 84 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.MISMATCH_FIELD, BUNDLE_KEY_MISMATCH_FIELD); 85 FAILURE_TYPE_TO_KEY.put(FAILURE_TYPE.CAUGHT_EXCEPTION, BUNDLE_KEY_CAUGHT_EXCEPTION); 86 } 87 88 @Override 89 protected void onCreate(Bundle savedInstanceState) { 90 super.onCreate(savedInstanceState); 91 92 mResultObserver = new DeviceResultObserver(); 93 start(); 94 mResultObserver.sendResult(getIntent()); 95 } 96 97 /** 98 * Start the signature test. 99 */ 100 @SuppressWarnings("unchecked") 101 private void start() { 102 SignatureTest sigTest = new SignatureTest(mResultObserver); 103 104 HashSet<String> excludeSet = getExcludedSet(); 105 106 Resources r = getResources(); 107 108 Class rClass = R.xml.class; 109 Field[]fs = rClass.getFields(); 110 for (Field f : fs) { 111 if (!excludeSet.contains(f.getName())) { 112 try { 113 sigTest.start(r.getXml(f.getInt(rClass))); 114 } catch (Exception e) { 115 mResultObserver.notifyFailure(FAILURE_TYPE.CAUGHT_EXCEPTION, e.getMessage(), 116 e.getMessage()); 117 } 118 } 119 } 120 } 121 122 /** 123 * Get the excluded package set, which is defined by res/raw/excludepackages.txt. 124 * 125 * @return The excluded package set. 126 */ 127 private HashSet<String> getExcludedSet() { 128 HashSet<String> excludeSet = new HashSet<String>(); 129 130 Resources r = getResources(); 131 InputStream excludepackage = r.openRawResource(R.raw.excludepackages); 132 BufferedReader reader = new BufferedReader(new InputStreamReader(excludepackage)); 133 try { 134 String p = null; 135 while (true) { 136 p = reader.readLine(); 137 if (p == null || p.equals("")) { 138 break; 139 } 140 excludeSet.add(p); 141 } 142 reader.close(); 143 } catch (IOException e) { 144 throw new RuntimeException(e); 145 } 146 147 return excludeSet; 148 } 149 150 Bundle mBundle; 151 152 /** 153 * This class is an implementation of the ResultObserver. And it aims to 154 * record the result in the Bundle, and send back to the Instrumentation class 155 * after all results has been recorded. 156 */ 157 final class DeviceResultObserver implements ResultObserver { 158 DeviceResultObserver() { 159 mBundle = new Bundle(); 160 mBundle.putStringArrayList(BUNDLE_KEY_MISSING_FIELD, new ArrayList<String>()); 161 mBundle.putStringArrayList(BUNDLE_KEY_MISSING_METHOD, new ArrayList<String>()); 162 mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_CLASS, 163 new ArrayList<String>()); 164 mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_FIELD, 165 new ArrayList<String>()); 166 mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_METHOD, 167 new ArrayList<String>()); 168 mBundle.putStringArrayList(BUNDLE_KEY_MISSING_CLASS, new ArrayList<String>()); 169 mBundle.putStringArrayList(BUNDLE_KEY_MISSING_INTERFACE, 170 new ArrayList<String>()); 171 mBundle.putStringArrayList(BUNDLE_KEY_MISMATCH_INTERFACE, 172 new ArrayList<String>()); 173 mBundle.putStringArrayList(BUNDLE_KEY_CAUGHT_EXCEPTION, 174 new ArrayList<String>()); 175 } 176 177 /** 178 * This method is called when all the results has been recorded. And this method 179 * will save the results in IBinder and send back to the Instrumentation class. 180 * 181 * @param i The intent to carry the result. 182 */ 183 @SuppressWarnings("deprecation") 184 public void sendResult(Intent i) { 185 SignatureTestLog.d("Send result"); 186 if ((mBundle.getStringArrayList(BUNDLE_KEY_MISSING_FIELD).size() == 0) 187 && (mBundle.getStringArrayList(BUNDLE_KEY_MISSING_CLASS).size() == 0) 188 && (mBundle.getStringArrayList(BUNDLE_KEY_MISSING_METHOD).size() == 0) 189 && (mBundle.getStringArrayList(BUNDLE_KEY_MISSING_INTERFACE).size() == 0) 190 && (mBundle.getStringArrayList( 191 BUNDLE_KEY_MISMATCH_CLASS).size() == 0) 192 && (mBundle.getStringArrayList( 193 BUNDLE_KEY_MISMATCH_FIELD).size() == 0) 194 && (mBundle.getStringArrayList( 195 BUNDLE_KEY_MISMATCH_INTERFACE).size() == 0) 196 && (mBundle.getStringArrayList( 197 BUNDLE_KEY_MISMATCH_METHOD).size() == 0) 198 && (mBundle.getStringArrayList( 199 BUNDLE_KEY_CAUGHT_EXCEPTION).size() == 0)) { 200 SignatureTestLog.d("PASS"); 201 mBundle.putBoolean(BUNDLE_KEY_RESULT, true); 202 } else { 203 SignatureTestLog.d("FAIL: " + mBundle.size()); 204 mBundle.putBoolean(BUNDLE_KEY_RESULT, false); 205 } 206 } 207 208 public void notifyFailure(FAILURE_TYPE type, 209 String name, 210 String errorMessage) { 211 SignatureTestLog.d("Failure: "); 212 SignatureTestLog.d(" Type: " + type); 213 SignatureTestLog.d(" Name: " + name); 214 SignatureTestLog.d(" Why : " + errorMessage); 215 mBundle.getStringArrayList(SignatureTestActivity.FAILURE_TYPE_TO_KEY.get(type)) 216 .add(name); 217 } 218 } 219} 220