1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file 5 * except in compliance with the License. You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software distributed under the 10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 11 * KIND, either express or implied. See the License for the specific language governing 12 * permissions and limitations under the License. 13 */ 14 15 package com.android.server.slice; 16 17 import android.annotation.NonNull; 18 import android.util.ArrayMap; 19 import android.util.ArraySet; 20 import android.util.Slog; 21 22 import com.android.server.slice.DirtyTracker.Persistable; 23 import com.android.server.slice.SlicePermissionManager.PkgUser; 24 25 import org.xmlpull.v1.XmlPullParser; 26 import org.xmlpull.v1.XmlPullParserException; 27 import org.xmlpull.v1.XmlSerializer; 28 29 import java.io.IOException; 30 import java.util.ArrayList; 31 import java.util.Collection; 32 import java.util.Objects; 33 34 public class SliceProviderPermissions implements DirtyTracker, Persistable { 35 36 private static final String TAG = "SliceProviderPermissions"; 37 38 static final String TAG_PROVIDER = "provider"; 39 private static final String TAG_AUTHORITY = "authority"; 40 private static final String TAG_PKG = "pkg"; 41 private static final String NAMESPACE = null; 42 43 private static final String ATTR_PKG = "pkg"; 44 private static final String ATTR_AUTHORITY = "authority"; 45 46 private final PkgUser mPkg; 47 private final ArrayMap<String, SliceAuthority> mAuths = new ArrayMap<>(); 48 private final DirtyTracker mTracker; 49 SliceProviderPermissions(@onNull PkgUser pkg, @NonNull DirtyTracker tracker)50 public SliceProviderPermissions(@NonNull PkgUser pkg, @NonNull DirtyTracker tracker) { 51 mPkg = pkg; 52 mTracker = tracker; 53 } 54 getPkg()55 public PkgUser getPkg() { 56 return mPkg; 57 } 58 getAuthorities()59 public synchronized Collection<SliceAuthority> getAuthorities() { 60 return new ArrayList<>(mAuths.values()); 61 } 62 getOrCreateAuthority(String authority)63 public synchronized SliceAuthority getOrCreateAuthority(String authority) { 64 SliceAuthority ret = mAuths.get(authority); 65 if (ret == null) { 66 ret = new SliceAuthority(authority, this); 67 mAuths.put(authority, ret); 68 onPersistableDirty(ret); 69 } 70 return ret; 71 } 72 73 @Override onPersistableDirty(Persistable obj)74 public void onPersistableDirty(Persistable obj) { 75 mTracker.onPersistableDirty(this); 76 } 77 78 @Override getFileName()79 public String getFileName() { 80 return getFileName(mPkg); 81 } 82 writeTo(XmlSerializer out)83 public synchronized void writeTo(XmlSerializer out) throws IOException { 84 out.startTag(NAMESPACE, TAG_PROVIDER); 85 out.attribute(NAMESPACE, ATTR_PKG, mPkg.toString()); 86 87 final int N = mAuths.size(); 88 for (int i = 0; i < N; i++) { 89 out.startTag(NAMESPACE, TAG_AUTHORITY); 90 out.attribute(NAMESPACE, ATTR_AUTHORITY, mAuths.valueAt(i).mAuthority); 91 92 mAuths.valueAt(i).writeTo(out); 93 94 out.endTag(NAMESPACE, TAG_AUTHORITY); 95 } 96 97 out.endTag(NAMESPACE, TAG_PROVIDER); 98 } 99 createFrom(XmlPullParser parser, DirtyTracker tracker)100 public static SliceProviderPermissions createFrom(XmlPullParser parser, DirtyTracker tracker) 101 throws XmlPullParserException, IOException { 102 // Get to the beginning of the provider. 103 while (parser.getEventType() != XmlPullParser.START_TAG 104 || !TAG_PROVIDER.equals(parser.getName())) { 105 parser.next(); 106 } 107 int depth = parser.getDepth(); 108 PkgUser pkgUser = new PkgUser(parser.getAttributeValue(NAMESPACE, ATTR_PKG)); 109 SliceProviderPermissions provider = new SliceProviderPermissions(pkgUser, tracker); 110 parser.next(); 111 112 while (parser.getDepth() > depth) { 113 if (parser.getEventType() == XmlPullParser.START_TAG 114 && TAG_AUTHORITY.equals(parser.getName())) { 115 try { 116 SliceAuthority authority = new SliceAuthority( 117 parser.getAttributeValue(NAMESPACE, ATTR_AUTHORITY), provider); 118 authority.readFrom(parser); 119 provider.mAuths.put(authority.getAuthority(), authority); 120 } catch (IllegalArgumentException e) { 121 Slog.e(TAG, "Couldn't read PkgUser", e); 122 } 123 } 124 125 parser.next(); 126 } 127 return provider; 128 } 129 getFileName(PkgUser pkg)130 public static String getFileName(PkgUser pkg) { 131 return String.format("provider_%s", pkg.toString()); 132 } 133 134 public static class SliceAuthority implements Persistable { 135 private final String mAuthority; 136 private final DirtyTracker mTracker; 137 private final ArraySet<PkgUser> mPkgs = new ArraySet<>(); 138 SliceAuthority(String authority, DirtyTracker tracker)139 public SliceAuthority(String authority, DirtyTracker tracker) { 140 mAuthority = authority; 141 mTracker = tracker; 142 } 143 getAuthority()144 public String getAuthority() { 145 return mAuthority; 146 } 147 addPkg(PkgUser pkg)148 public synchronized void addPkg(PkgUser pkg) { 149 if (mPkgs.add(pkg)) { 150 mTracker.onPersistableDirty(this); 151 } 152 } 153 removePkg(PkgUser pkg)154 public synchronized void removePkg(PkgUser pkg) { 155 if (mPkgs.remove(pkg)) { 156 mTracker.onPersistableDirty(this); 157 } 158 } 159 getPkgs()160 public synchronized Collection<PkgUser> getPkgs() { 161 return new ArraySet<>(mPkgs); 162 } 163 164 @Override getFileName()165 public String getFileName() { 166 return null; 167 } 168 writeTo(XmlSerializer out)169 public synchronized void writeTo(XmlSerializer out) throws IOException { 170 final int N = mPkgs.size(); 171 for (int i = 0; i < N; i++) { 172 out.startTag(NAMESPACE, TAG_PKG); 173 out.text(mPkgs.valueAt(i).toString()); 174 out.endTag(NAMESPACE, TAG_PKG); 175 } 176 } 177 readFrom(XmlPullParser parser)178 public synchronized void readFrom(XmlPullParser parser) 179 throws IOException, XmlPullParserException { 180 parser.next(); 181 int depth = parser.getDepth(); 182 while (parser.getDepth() >= depth) { 183 if (parser.getEventType() == XmlPullParser.START_TAG 184 && TAG_PKG.equals(parser.getName())) { 185 mPkgs.add(new PkgUser(parser.nextText())); 186 } 187 parser.next(); 188 } 189 } 190 191 @Override equals(Object obj)192 public boolean equals(Object obj) { 193 if (!getClass().equals(obj != null ? obj.getClass() : null)) return false; 194 SliceAuthority other = (SliceAuthority) obj; 195 return Objects.equals(mAuthority, other.mAuthority) 196 && Objects.equals(mPkgs, other.mPkgs); 197 } 198 199 @Override toString()200 public String toString() { 201 return String.format("(%s: %s)", mAuthority, mPkgs.toString()); 202 } 203 } 204 } 205