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