1 /* 2 * Copyright (C) 2015 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 17 package android.content.pm; 18 19 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; 20 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; 21 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; 22 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; 23 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; 24 25 import android.annotation.SystemApi; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.text.TextUtils; 29 import android.util.ArraySet; 30 import android.util.Log; 31 32 import com.android.internal.util.XmlUtils; 33 import com.android.modules.utils.TypedXmlPullParser; 34 import com.android.modules.utils.TypedXmlSerializer; 35 36 import org.xmlpull.v1.XmlPullParser; 37 import org.xmlpull.v1.XmlPullParserException; 38 39 import java.io.IOException; 40 import java.util.ArrayList; 41 import java.util.Set; 42 43 /** 44 * The {@link com.android.server.pm.PackageManagerService} maintains some 45 * {@link IntentFilterVerificationInfo}s for each domain / package name. 46 * 47 * @hide 48 */ 49 @SystemApi 50 public final class IntentFilterVerificationInfo implements Parcelable { 51 private static final String TAG = IntentFilterVerificationInfo.class.getName(); 52 53 private static final String TAG_DOMAIN = "domain"; 54 private static final String ATTR_DOMAIN_NAME = "name"; 55 private static final String ATTR_PACKAGE_NAME = "packageName"; 56 private static final String ATTR_STATUS = "status"; 57 58 private ArraySet<String> mDomains = new ArraySet<>(); 59 private String mPackageName; 60 private int mStatus; 61 62 /** @hide */ IntentFilterVerificationInfo()63 public IntentFilterVerificationInfo() { 64 mPackageName = null; 65 mStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; 66 } 67 68 /** @hide */ IntentFilterVerificationInfo(String packageName, ArraySet<String> domains)69 public IntentFilterVerificationInfo(String packageName, ArraySet<String> domains) { 70 mPackageName = packageName; 71 mDomains = domains; 72 mStatus = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; 73 } 74 75 /** @hide */ IntentFilterVerificationInfo(TypedXmlPullParser parser)76 public IntentFilterVerificationInfo(TypedXmlPullParser parser) 77 throws IOException, XmlPullParserException { 78 readFromXml(parser); 79 } 80 81 /** @hide */ IntentFilterVerificationInfo(Parcel source)82 public IntentFilterVerificationInfo(Parcel source) { 83 readFromParcel(source); 84 } 85 getPackageName()86 public String getPackageName() { 87 return mPackageName; 88 } 89 getStatus()90 public int getStatus() { 91 return mStatus; 92 } 93 94 /** @hide */ setStatus(int s)95 public void setStatus(int s) { 96 if (s >= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED && 97 s <= INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER) { 98 mStatus = s; 99 } else { 100 Log.w(TAG, "Trying to set a non supported status: " + s); 101 } 102 } 103 getDomains()104 public Set<String> getDomains() { 105 return mDomains; 106 } 107 108 /** @hide */ setDomains(ArraySet<String> list)109 public void setDomains(ArraySet<String> list) { 110 mDomains = list; 111 } 112 113 /** @hide */ getDomainsString()114 public String getDomainsString() { 115 StringBuilder sb = new StringBuilder(); 116 for (String str : mDomains) { 117 if (sb.length() > 0) { 118 sb.append(" "); 119 } 120 sb.append(str); 121 } 122 return sb.toString(); 123 } 124 getStringFromXml(TypedXmlPullParser parser, String attribute, String defaultValue)125 String getStringFromXml(TypedXmlPullParser parser, String attribute, String defaultValue) { 126 String value = parser.getAttributeValue(null, attribute); 127 if (value == null) { 128 String msg = "Missing element under " + TAG +": " + attribute + " at " + 129 parser.getPositionDescription(); 130 Log.w(TAG, msg); 131 return defaultValue; 132 } else { 133 return value; 134 } 135 } 136 getIntFromXml(TypedXmlPullParser parser, String attribute, int defaultValue)137 int getIntFromXml(TypedXmlPullParser parser, String attribute, int defaultValue) { 138 return parser.getAttributeInt(null, attribute, defaultValue); 139 } 140 141 /** @hide */ readFromXml(TypedXmlPullParser parser)142 public void readFromXml(TypedXmlPullParser parser) throws XmlPullParserException, 143 IOException { 144 mPackageName = getStringFromXml(parser, ATTR_PACKAGE_NAME, null); 145 if (mPackageName == null) { 146 Log.e(TAG, "Package name cannot be null!"); 147 } 148 int status = getIntFromXml(parser, ATTR_STATUS, -1); 149 if (status == -1) { 150 Log.e(TAG, "Unknown status value: " + status); 151 } 152 mStatus = status; 153 154 int outerDepth = parser.getDepth(); 155 int type; 156 while ((type=parser.next()) != XmlPullParser.END_DOCUMENT 157 && (type != XmlPullParser.END_TAG 158 || parser.getDepth() > outerDepth)) { 159 if (type == XmlPullParser.END_TAG 160 || type == XmlPullParser.TEXT) { 161 continue; 162 } 163 164 String tagName = parser.getName(); 165 if (tagName.equals(TAG_DOMAIN)) { 166 String name = getStringFromXml(parser, ATTR_DOMAIN_NAME, null); 167 if (!TextUtils.isEmpty(name)) { 168 mDomains.add(name); 169 } 170 } else { 171 Log.w(TAG, "Unknown tag parsing IntentFilter: " + tagName); 172 } 173 XmlUtils.skipCurrentTag(parser); 174 } 175 } 176 177 /** @hide */ writeToXml(TypedXmlSerializer serializer)178 public void writeToXml(TypedXmlSerializer serializer) throws IOException { 179 serializer.attribute(null, ATTR_PACKAGE_NAME, mPackageName); 180 serializer.attributeInt(null, ATTR_STATUS, mStatus); 181 for (String str : mDomains) { 182 serializer.startTag(null, TAG_DOMAIN); 183 serializer.attribute(null, ATTR_DOMAIN_NAME, str); 184 serializer.endTag(null, TAG_DOMAIN); 185 } 186 } 187 188 /** @hide */ getStatusString()189 public String getStatusString() { 190 return getStatusStringFromValue(((long) mStatus) << 32); 191 } 192 193 /** @hide */ getStatusStringFromValue(long val)194 public static String getStatusStringFromValue(long val) { 195 StringBuilder sb = new StringBuilder(); 196 switch ((int)(val >> 32)) { 197 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: 198 sb.append("always : "); 199 sb.append(Long.toHexString(val & 0x00000000FFFFFFFF)); 200 break; 201 202 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: 203 sb.append("ask"); 204 break; 205 206 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: 207 sb.append("never"); 208 break; 209 210 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK: 211 sb.append("always-ask"); 212 break; 213 214 case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: 215 default: 216 sb.append("undefined"); 217 break; 218 } 219 return sb.toString(); 220 } 221 222 @Override describeContents()223 public int describeContents() { 224 return 0; 225 } 226 readFromParcel(Parcel source)227 private void readFromParcel(Parcel source) { 228 mPackageName = source.readString(); 229 mStatus = source.readInt(); 230 ArrayList<String> list = new ArrayList<>(); 231 source.readStringList(list); 232 mDomains.addAll(list); 233 } 234 235 @Override writeToParcel(Parcel dest, int flags)236 public void writeToParcel(Parcel dest, int flags) { 237 dest.writeString(mPackageName); 238 dest.writeInt(mStatus); 239 dest.writeStringList(new ArrayList<>(mDomains)); 240 } 241 242 public static final @android.annotation.NonNull Creator<IntentFilterVerificationInfo> CREATOR = 243 new Creator<IntentFilterVerificationInfo>() { 244 public IntentFilterVerificationInfo createFromParcel(Parcel source) { 245 return new IntentFilterVerificationInfo(source); 246 } 247 public IntentFilterVerificationInfo[] newArray(int size) { 248 return new IntentFilterVerificationInfo[size]; 249 } 250 }; 251 } 252