1 /* 2 * Copyright 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.Intent; 20 import android.content.IntentFilter; 21 import android.os.UserHandle; 22 import android.util.Log; 23 import android.util.TypedXmlPullParser; 24 import android.util.TypedXmlSerializer; 25 26 import com.android.internal.util.XmlUtils; 27 import com.android.server.utils.SnapshotCache; 28 29 import org.xmlpull.v1.XmlPullParser; 30 import org.xmlpull.v1.XmlPullParserException; 31 32 import java.io.IOException; 33 34 /** 35 * The {@link PackageManagerService} maintains some {@link CrossProfileIntentFilter}s for each user. 36 * If an {@link Intent} matches the {@link CrossProfileIntentFilter}, then activities in the user 37 * {@link #mTargetUserId} can access it. 38 */ 39 class CrossProfileIntentFilter extends WatchedIntentFilter { 40 private static final String ATTR_TARGET_USER_ID = "targetUserId"; 41 private static final String ATTR_FLAGS = "flags"; 42 private static final String ATTR_OWNER_PACKAGE = "ownerPackage"; 43 private static final String ATTR_FILTER = "filter"; 44 45 private static final String TAG = "CrossProfileIntentFilter"; 46 47 // If the intent matches the IntentFilter, then it can be forwarded to this userId. 48 final int mTargetUserId; 49 final String mOwnerPackage; // packageName of the app. 50 final int mFlags; 51 52 // The cache for snapshots, so they are not rebuilt if the base object has not 53 // changed. 54 final SnapshotCache<CrossProfileIntentFilter> mSnapshot; 55 makeCache()56 private SnapshotCache makeCache() { 57 return new SnapshotCache<CrossProfileIntentFilter>(this, this) { 58 @Override 59 public CrossProfileIntentFilter createSnapshot() { 60 CrossProfileIntentFilter s = new CrossProfileIntentFilter(mSource); 61 s.seal(); 62 return s; 63 }}; 64 } 65 66 CrossProfileIntentFilter(IntentFilter filter, String ownerPackage, int targetUserId, 67 int flags) { 68 super(filter); 69 mTargetUserId = targetUserId; 70 mOwnerPackage = ownerPackage; 71 mFlags = flags; 72 mSnapshot = makeCache(); 73 } 74 75 CrossProfileIntentFilter(WatchedIntentFilter filter, String ownerPackage, int targetUserId, 76 int flags) { 77 this(filter.mFilter, ownerPackage, targetUserId, flags); 78 } 79 80 // Copy constructor used only to create a snapshot. 81 private CrossProfileIntentFilter(CrossProfileIntentFilter f) { 82 super(f); 83 mTargetUserId = f.mTargetUserId; 84 mOwnerPackage = f.mOwnerPackage; 85 mFlags = f.mFlags; 86 mSnapshot = new SnapshotCache.Sealed(); 87 } 88 89 public int getTargetUserId() { 90 return mTargetUserId; 91 } 92 93 public int getFlags() { 94 return mFlags; 95 } 96 97 public String getOwnerPackage() { 98 return mOwnerPackage; 99 } 100 101 CrossProfileIntentFilter(TypedXmlPullParser parser) throws XmlPullParserException, IOException { 102 mTargetUserId = parser.getAttributeInt(null, ATTR_TARGET_USER_ID, UserHandle.USER_NULL); 103 mOwnerPackage = getStringFromXml(parser, ATTR_OWNER_PACKAGE, ""); 104 mFlags = parser.getAttributeInt(null, ATTR_FLAGS, 0); 105 mSnapshot = makeCache(); 106 107 int outerDepth = parser.getDepth(); 108 String tagName = parser.getName(); 109 int type; 110 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT 111 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { 112 tagName = parser.getName(); 113 if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { 114 continue; 115 } else if (type == XmlPullParser.START_TAG) { 116 if (tagName.equals(ATTR_FILTER)) { 117 break; 118 } else { 119 String msg = "Unknown element under " 120 + Settings.TAG_CROSS_PROFILE_INTENT_FILTERS + ": " + tagName + " at " 121 + parser.getPositionDescription(); 122 PackageManagerService.reportSettingsProblem(Log.WARN, msg); 123 XmlUtils.skipCurrentTag(parser); 124 } 125 } 126 } 127 if (tagName.equals(ATTR_FILTER)) { 128 mFilter.readFromXml(parser); 129 } else { 130 String msg = "Missing element under " + TAG + ": " + ATTR_FILTER + 131 " at " + parser.getPositionDescription(); 132 PackageManagerService.reportSettingsProblem(Log.WARN, msg); 133 XmlUtils.skipCurrentTag(parser); 134 } 135 } 136 137 private String getStringFromXml(TypedXmlPullParser parser, String attribute, 138 String defaultValue) { 139 String value = parser.getAttributeValue(null, attribute); 140 if (value == null) { 141 String msg = "Missing element under " + TAG +": " + attribute + " at " + 142 parser.getPositionDescription(); 143 PackageManagerService.reportSettingsProblem(Log.WARN, msg); 144 return defaultValue; 145 } else { 146 return value; 147 } 148 } 149 150 public void writeToXml(TypedXmlSerializer serializer) throws IOException { 151 serializer.attributeInt(null, ATTR_TARGET_USER_ID, mTargetUserId); 152 serializer.attributeInt(null, ATTR_FLAGS, mFlags); 153 serializer.attribute(null, ATTR_OWNER_PACKAGE, mOwnerPackage); 154 serializer.startTag(null, ATTR_FILTER); 155 mFilter.writeToXml(serializer); 156 serializer.endTag(null, ATTR_FILTER); 157 } 158 159 @Override 160 public String toString() { 161 return "CrossProfileIntentFilter{0x" + Integer.toHexString(System.identityHashCode(this)) 162 + " " + Integer.toString(mTargetUserId) + "}"; 163 } 164 165 boolean equalsIgnoreFilter(CrossProfileIntentFilter other) { 166 return mTargetUserId == other.mTargetUserId 167 && mOwnerPackage.equals(other.mOwnerPackage) 168 && mFlags == other.mFlags; 169 } 170 171 public CrossProfileIntentFilter snapshot() { 172 return mSnapshot.snapshot(); 173 } 174 } 175