1 /* 2 * Copyright (C) 2006 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.am; 18 19 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 20 21 import android.app.ContentProviderHolder; 22 import android.content.ComponentName; 23 import android.content.IContentProvider; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.ProviderInfo; 26 import android.os.IBinder; 27 import android.os.IBinder.DeathRecipient; 28 import android.os.Process; 29 import android.os.RemoteException; 30 import android.os.UserHandle; 31 import android.util.ArrayMap; 32 import android.util.Slog; 33 34 import com.android.internal.app.procstats.AssociationState; 35 import com.android.internal.app.procstats.ProcessStats; 36 37 import java.io.PrintWriter; 38 import java.util.ArrayList; 39 40 final class ContentProviderRecord implements ComponentName.WithComponentName { 41 final ActivityManagerService service; 42 public final ProviderInfo info; 43 final int uid; 44 final ApplicationInfo appInfo; 45 final ComponentName name; 46 final boolean singleton; 47 public IContentProvider provider; 48 public boolean noReleaseNeeded; 49 // All attached clients 50 final ArrayList<ContentProviderConnection> connections 51 = new ArrayList<ContentProviderConnection>(); 52 //final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>(); 53 // Handles for non-framework processes supported by this provider 54 ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle; 55 // Count for external process for which we have no handles. 56 int externalProcessNoHandleCount; 57 ProcessRecord proc; // if non-null, hosting process. 58 ProcessRecord launchingApp; // if non-null, waiting for this app to be launched. 59 String stringName; 60 String shortStringName; 61 ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, ApplicationInfo ai, ComponentName _name, boolean _singleton)62 public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info, 63 ApplicationInfo ai, ComponentName _name, boolean _singleton) { 64 service = _service; 65 info = _info; 66 uid = ai.uid; 67 appInfo = ai; 68 name = _name; 69 singleton = _singleton; 70 noReleaseNeeded = (uid == 0 || uid == Process.SYSTEM_UID) 71 && (_name == null || !"com.android.settings".equals(_name.getPackageName())); 72 } 73 ContentProviderRecord(ContentProviderRecord cpr)74 public ContentProviderRecord(ContentProviderRecord cpr) { 75 service = cpr.service; 76 info = cpr.info; 77 uid = cpr.uid; 78 appInfo = cpr.appInfo; 79 name = cpr.name; 80 singleton = cpr.singleton; 81 noReleaseNeeded = cpr.noReleaseNeeded; 82 } 83 newHolder(ContentProviderConnection conn)84 public ContentProviderHolder newHolder(ContentProviderConnection conn) { 85 ContentProviderHolder holder = new ContentProviderHolder(info); 86 holder.provider = provider; 87 holder.noReleaseNeeded = noReleaseNeeded; 88 holder.connection = conn; 89 return holder; 90 } 91 setProcess(ProcessRecord proc)92 public void setProcess(ProcessRecord proc) { 93 this.proc = proc; 94 if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS) { 95 for (int iconn = connections.size() - 1; iconn >= 0; iconn--) { 96 final ContentProviderConnection conn = connections.get(iconn); 97 if (proc != null) { 98 conn.startAssociationIfNeeded(); 99 } else { 100 conn.stopAssociation(); 101 } 102 } 103 if (externalProcessTokenToHandle != null) { 104 for (int iext = externalProcessTokenToHandle.size() - 1; iext >= 0; iext--) { 105 final ExternalProcessHandle handle = externalProcessTokenToHandle.valueAt(iext); 106 if (proc != null) { 107 handle.startAssociationIfNeeded(this); 108 } else { 109 handle.stopAssociation(); 110 } 111 } 112 } 113 } 114 } 115 canRunHere(ProcessRecord app)116 public boolean canRunHere(ProcessRecord app) { 117 return (info.multiprocess || info.processName.equals(app.processName)) 118 && uid == app.info.uid; 119 } 120 addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag)121 public void addExternalProcessHandleLocked(IBinder token, int callingUid, String callingTag) { 122 if (token == null) { 123 externalProcessNoHandleCount++; 124 } else { 125 if (externalProcessTokenToHandle == null) { 126 externalProcessTokenToHandle = new ArrayMap<>(); 127 } 128 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 129 if (handle == null) { 130 handle = new ExternalProcessHandle(token, callingUid, callingTag); 131 externalProcessTokenToHandle.put(token, handle); 132 handle.startAssociationIfNeeded(this); 133 } 134 handle.mAcquisitionCount++; 135 } 136 } 137 removeExternalProcessHandleLocked(IBinder token)138 public boolean removeExternalProcessHandleLocked(IBinder token) { 139 if (hasExternalProcessHandles()) { 140 boolean hasHandle = false; 141 if (externalProcessTokenToHandle != null) { 142 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 143 if (handle != null) { 144 hasHandle = true; 145 handle.mAcquisitionCount--; 146 if (handle.mAcquisitionCount == 0) { 147 removeExternalProcessHandleInternalLocked(token); 148 return true; 149 } 150 } 151 } 152 if (!hasHandle) { 153 externalProcessNoHandleCount--; 154 return true; 155 } 156 } 157 return false; 158 } 159 removeExternalProcessHandleInternalLocked(IBinder token)160 private void removeExternalProcessHandleInternalLocked(IBinder token) { 161 ExternalProcessHandle handle = externalProcessTokenToHandle.get(token); 162 handle.unlinkFromOwnDeathLocked(); 163 handle.stopAssociation(); 164 externalProcessTokenToHandle.remove(token); 165 if (externalProcessTokenToHandle.size() == 0) { 166 externalProcessTokenToHandle = null; 167 } 168 } 169 hasExternalProcessHandles()170 public boolean hasExternalProcessHandles() { 171 return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0); 172 } 173 hasConnectionOrHandle()174 public boolean hasConnectionOrHandle() { 175 return !connections.isEmpty() || hasExternalProcessHandles(); 176 } 177 dump(PrintWriter pw, String prefix, boolean full)178 void dump(PrintWriter pw, String prefix, boolean full) { 179 if (full) { 180 pw.print(prefix); pw.print("package="); 181 pw.print(info.applicationInfo.packageName); 182 pw.print(" process="); pw.println(info.processName); 183 } 184 pw.print(prefix); pw.print("proc="); pw.println(proc); 185 if (launchingApp != null) { 186 pw.print(prefix); pw.print("launchingApp="); pw.println(launchingApp); 187 } 188 if (full) { 189 pw.print(prefix); pw.print("uid="); pw.print(uid); 190 pw.print(" provider="); pw.println(provider); 191 } 192 if (singleton) { 193 pw.print(prefix); pw.print("singleton="); pw.println(singleton); 194 } 195 pw.print(prefix); pw.print("authority="); pw.println(info.authority); 196 if (full) { 197 if (info.isSyncable || info.multiprocess || info.initOrder != 0) { 198 pw.print(prefix); pw.print("isSyncable="); pw.print(info.isSyncable); 199 pw.print(" multiprocess="); pw.print(info.multiprocess); 200 pw.print(" initOrder="); pw.println(info.initOrder); 201 } 202 } 203 if (full) { 204 if (hasExternalProcessHandles()) { 205 pw.print(prefix); pw.print("externals:"); 206 if (externalProcessTokenToHandle != null) { 207 pw.print(" w/token="); 208 pw.print(externalProcessTokenToHandle.size()); 209 } 210 if (externalProcessNoHandleCount > 0) { 211 pw.print(" notoken="); 212 pw.print(externalProcessNoHandleCount); 213 } 214 pw.println(); 215 } 216 } else { 217 if (connections.size() > 0 || externalProcessNoHandleCount > 0) { 218 pw.print(prefix); pw.print(connections.size()); 219 pw.print(" connections, "); pw.print(externalProcessNoHandleCount); 220 pw.println(" external handles"); 221 } 222 } 223 if (connections.size() > 0) { 224 if (full) { 225 pw.print(prefix); pw.println("Connections:"); 226 } 227 for (int i=0; i<connections.size(); i++) { 228 ContentProviderConnection conn = connections.get(i); 229 pw.print(prefix); pw.print(" -> "); pw.println(conn.toClientString()); 230 if (conn.provider != this) { 231 pw.print(prefix); pw.print(" *** WRONG PROVIDER: "); 232 pw.println(conn.provider); 233 } 234 } 235 } 236 } 237 238 @Override toString()239 public String toString() { 240 if (stringName != null) { 241 return stringName; 242 } 243 StringBuilder sb = new StringBuilder(128); 244 sb.append("ContentProviderRecord{"); 245 sb.append(Integer.toHexString(System.identityHashCode(this))); 246 sb.append(" u"); 247 sb.append(UserHandle.getUserId(uid)); 248 sb.append(' '); 249 sb.append(name.flattenToShortString()); 250 sb.append('}'); 251 return stringName = sb.toString(); 252 } 253 toShortString()254 public String toShortString() { 255 if (shortStringName != null) { 256 return shortStringName; 257 } 258 StringBuilder sb = new StringBuilder(128); 259 sb.append(Integer.toHexString(System.identityHashCode(this))); 260 sb.append('/'); 261 sb.append(name.flattenToShortString()); 262 return shortStringName = sb.toString(); 263 } 264 265 // This class represents a handle from an external process to a provider. 266 private class ExternalProcessHandle implements DeathRecipient { 267 private static final String LOG_TAG = "ExternalProcessHanldle"; 268 269 final IBinder mToken; 270 final int mOwningUid; 271 final String mOwningProcessName; 272 int mAcquisitionCount; 273 AssociationState.SourceState mAssociation; 274 ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName)275 public ExternalProcessHandle(IBinder token, int owningUid, String owningProcessName) { 276 mToken = token; 277 mOwningUid = owningUid; 278 mOwningProcessName = owningProcessName; 279 try { 280 token.linkToDeath(this, 0); 281 } catch (RemoteException re) { 282 Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re); 283 } 284 } 285 unlinkFromOwnDeathLocked()286 public void unlinkFromOwnDeathLocked() { 287 mToken.unlinkToDeath(this, 0); 288 } 289 startAssociationIfNeeded(ContentProviderRecord provider)290 public void startAssociationIfNeeded(ContentProviderRecord provider) { 291 // If we don't already have an active association, create one... but only if this 292 // is an association between two different processes. 293 if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS 294 && mAssociation == null && provider.proc != null 295 && (provider.appInfo.uid != mOwningUid 296 || !provider.info.processName.equals(mOwningProcessName))) { 297 ProcessStats.ProcessStateHolder holder = provider.proc.pkgList.get( 298 provider.name.getPackageName()); 299 if (holder == null) { 300 Slog.wtf(TAG_AM, "No package in referenced provider " 301 + provider.name.toShortString() + ": proc=" + provider.proc); 302 } else if (holder.pkg == null) { 303 Slog.wtf(TAG_AM, "Inactive holder in referenced provider " 304 + provider.name.toShortString() + ": proc=" + provider.proc); 305 } else { 306 mAssociation = holder.pkg.getAssociationStateLocked(holder.state, 307 provider.name.getClassName()).startSource(mOwningUid, 308 mOwningProcessName, null); 309 310 } 311 } 312 } 313 stopAssociation()314 public void stopAssociation() { 315 if (mAssociation != null) { 316 mAssociation.stop(); 317 mAssociation = null; 318 } 319 } 320 321 @Override binderDied()322 public void binderDied() { 323 synchronized (service) { 324 if (hasExternalProcessHandles() && 325 externalProcessTokenToHandle.get(mToken) != null) { 326 removeExternalProcessHandleInternalLocked(mToken); 327 } 328 } 329 } 330 } 331 getComponentName()332 public ComponentName getComponentName() { 333 return name; 334 } 335 } 336