1 /*
2  * Copyright (C) 2014 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 com.android.server.pm;
18 
19 import android.content.ComponentName;
20 import android.content.IntentFilter;
21 import android.util.Log;
22 
23 import com.android.internal.util.XmlUtils;
24 import com.android.modules.utils.TypedXmlPullParser;
25 import com.android.modules.utils.TypedXmlSerializer;
26 import com.android.server.utils.SnapshotCache;
27 
28 import org.xmlpull.v1.XmlPullParser;
29 import org.xmlpull.v1.XmlPullParserException;
30 
31 import java.io.IOException;
32 
33 class PersistentPreferredActivity extends WatchedIntentFilter {
34     private static final String ATTR_NAME = "name"; // component name
35     private static final String ATTR_FILTER = "filter"; // filter
36     private static final String ATTR_SET_BY_DPM = "set-by-dpm"; // set by DPM
37 
38     private static final String TAG = "PersistentPreferredActivity";
39 
40     private static final boolean DEBUG_FILTERS = false;
41 
42     final ComponentName mComponent;
43     final boolean mIsSetByDpm;
44 
45     // The cache for snapshots, so they are not rebuilt if the base object has not
46     // changed.
47     final SnapshotCache<PersistentPreferredActivity> mSnapshot;
48 
makeCache()49     private SnapshotCache makeCache() {
50         return new SnapshotCache<PersistentPreferredActivity>(this, this) {
51             @Override
52             public PersistentPreferredActivity createSnapshot() {
53                 PersistentPreferredActivity s = new PersistentPreferredActivity(mSource);
54                 s.seal();
55                 return s;
56             }};
57     }
58 
59     PersistentPreferredActivity(IntentFilter filter, ComponentName activity, boolean isSetByDpm) {
60         super(filter);
61         mComponent = activity;
62         mIsSetByDpm = isSetByDpm;
63         mSnapshot = makeCache();
64     }
65 
66     PersistentPreferredActivity(WatchedIntentFilter filter, ComponentName activity,
67             boolean isSetByDpm) {
68         this(filter.mFilter, activity, isSetByDpm);
69     }
70 
71     // Copy constructor used only to create a snapshot
72     private PersistentPreferredActivity(PersistentPreferredActivity f) {
73         super(f);
74         mComponent = f.mComponent;
75         mIsSetByDpm = f.mIsSetByDpm;
76         mSnapshot = new SnapshotCache.Sealed();
77     }
78 
79     PersistentPreferredActivity(TypedXmlPullParser parser)
80             throws XmlPullParserException, IOException {
81         String shortComponent = parser.getAttributeValue(null, ATTR_NAME);
82         mComponent = ComponentName.unflattenFromString(shortComponent);
83         if (mComponent == null) {
84             PackageManagerService.reportSettingsProblem(Log.WARN,
85                     "Error in package manager settings: " +
86                             "Bad activity name " + shortComponent +
87                             " at " + parser.getPositionDescription());
88         }
89         mIsSetByDpm = parser.getAttributeBoolean(null, ATTR_SET_BY_DPM, false);
90 
91         int outerDepth = parser.getDepth();
92         String tagName = parser.getName();
93         int type;
94         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
95                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
96             tagName = parser.getName();
97             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
98                 continue;
99             } else if (type == XmlPullParser.START_TAG) {
100                 if (tagName.equals(ATTR_FILTER)) {
101                     break;
102                 } else {
103                     PackageManagerService.reportSettingsProblem(Log.WARN,
104                             "Unknown element: " + tagName +
105                             " at " + parser.getPositionDescription());
106                     XmlUtils.skipCurrentTag(parser);
107                 }
108             }
109         }
110         if (tagName.equals(ATTR_FILTER)) {
111             mFilter.readFromXml(parser);
112         } else {
113             PackageManagerService.reportSettingsProblem(Log.WARN,
114                     "Missing element filter at " +
115                     parser.getPositionDescription());
116             XmlUtils.skipCurrentTag(parser);
117         }
118         mSnapshot = makeCache();
119     }
120 
121     public void writeToXml(TypedXmlSerializer serializer) throws IOException {
122         serializer.attribute(null, ATTR_NAME, mComponent.flattenToShortString());
123         serializer.attributeBoolean(null, ATTR_SET_BY_DPM, mIsSetByDpm);
124         serializer.startTag(null, ATTR_FILTER);
125         mFilter.writeToXml(serializer);
126         serializer.endTag(null, ATTR_FILTER);
127     }
128 
129     public IntentFilter getIntentFilter() {
130         return mFilter;
131     }
132 
133     @Override
134     public String toString() {
135         return "PersistentPreferredActivity{0x" + Integer.toHexString(System.identityHashCode(this))
136                 + " " + mComponent.flattenToShortString()
137                 + ", mIsSetByDpm=" + mIsSetByDpm + "}";
138     }
139 
140     public PersistentPreferredActivity snapshot() {
141         return mSnapshot.snapshot();
142     }
143 }
144