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