1 /* 2 * Copyright (C) 2016 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 package android.service.autofill; 17 18 import android.Manifest; 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.AppGlobals; 22 import android.content.ComponentName; 23 import android.content.pm.PackageManager; 24 import android.content.pm.ServiceInfo; 25 import android.content.res.Resources; 26 import android.content.res.TypedArray; 27 import android.content.res.XmlResourceParser; 28 import android.os.RemoteException; 29 import android.util.AttributeSet; 30 import android.util.Log; 31 import android.util.Xml; 32 33 import com.android.internal.R; 34 35 import org.xmlpull.v1.XmlPullParser; 36 import org.xmlpull.v1.XmlPullParserException; 37 38 import java.io.IOException; 39 40 /** 41 * {@link ServiceInfo} and meta-data about an {@link AutofillService}. 42 * 43 * @hide 44 */ 45 public final class AutofillServiceInfo { 46 private static final String TAG = "AutofillServiceInfo"; 47 48 private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle) 49 throws PackageManager.NameNotFoundException { 50 try { 51 ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo( 52 comp, 53 PackageManager.GET_META_DATA, 54 userHandle); 55 if (si != null) { 56 return si; 57 } 58 } catch (RemoteException e) { 59 } 60 throw new PackageManager.NameNotFoundException(comp.toString()); 61 } 62 63 @NonNull 64 private final ServiceInfo mServiceInfo; 65 66 @Nullable 67 private final String mSettingsActivity; 68 69 public AutofillServiceInfo(PackageManager pm, ComponentName comp, int userHandle) 70 throws PackageManager.NameNotFoundException { 71 this(pm, getServiceInfoOrThrow(comp, userHandle)); 72 } 73 74 public AutofillServiceInfo(PackageManager pm, ServiceInfo si) { 75 mServiceInfo = si; 76 final TypedArray metaDataArray = getMetaDataArray(pm, si); 77 if (metaDataArray != null) { 78 mSettingsActivity = metaDataArray 79 .getString(R.styleable.AutofillService_settingsActivity); 80 metaDataArray.recycle(); 81 } else { 82 mSettingsActivity = null; 83 } 84 } 85 86 /** 87 * Gets the meta-data as a {@link TypedArray}, or {@code null} if not provided, 88 * or throws if invalid. 89 */ 90 @Nullable 91 private static TypedArray getMetaDataArray(PackageManager pm, ServiceInfo si) { 92 // Check for permissions. 93 // TODO(b/37563972): remove support to BIND_AUTOFILL once clients use BIND_AUTOFILL_SERVICE 94 if (!Manifest.permission.BIND_AUTOFILL_SERVICE.equals(si.permission) 95 && !Manifest.permission.BIND_AUTOFILL.equals(si.permission)) { 96 Log.w(TAG, "AutofillService from '" + si.packageName + "' does not require permission " 97 + Manifest.permission.BIND_AUTOFILL_SERVICE); 98 throw new SecurityException("Service does not require permission " 99 + Manifest.permission.BIND_AUTOFILL_SERVICE); 100 } 101 102 // Get the AutoFill metadata, if declared. 103 XmlResourceParser parser = si.loadXmlMetaData(pm, AutofillService.SERVICE_META_DATA); 104 if (parser == null) { 105 return null; 106 } 107 108 // Parse service info and get the <autofill-service> tag as an AttributeSet. 109 AttributeSet attrs; 110 try { 111 // Move the XML parser to the first tag. 112 try { 113 int type; 114 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 115 && type != XmlPullParser.START_TAG) { 116 } 117 } catch (XmlPullParserException | IOException e) { 118 Log.e(TAG, "Error parsing auto fill service meta-data", e); 119 return null; 120 } 121 122 if (!"autofill-service".equals(parser.getName())) { 123 Log.e(TAG, "Meta-data does not start with autofill-service tag"); 124 return null; 125 } 126 attrs = Xml.asAttributeSet(parser); 127 128 // Get resources required to read the AttributeSet. 129 Resources res; 130 try { 131 res = pm.getResourcesForApplication(si.applicationInfo); 132 } catch (PackageManager.NameNotFoundException e) { 133 Log.e(TAG, "Error getting application resources", e); 134 return null; 135 } 136 137 return res.obtainAttributes(attrs, R.styleable.AutofillService); 138 } finally { 139 parser.close(); 140 } 141 } 142 143 public ServiceInfo getServiceInfo() { 144 return mServiceInfo; 145 } 146 147 @Nullable 148 public String getSettingsActivity() { 149 return mSettingsActivity; 150 } 151 152 @Override 153 public String toString() { 154 return mServiceInfo == null ? "null" : mServiceInfo.toString(); 155 } 156 } 157