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