1 /* 2 * Copyright (C) 2012 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.DEBUG_PROVIDER; 20 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 21 import static com.android.server.am.ProcessList.UNKNOWN_ADJ; 22 23 import android.annotation.UserIdInt; 24 import android.os.Binder; 25 import android.os.SystemClock; 26 import android.util.Slog; 27 import android.util.TimeUtils; 28 29 import com.android.internal.annotations.GuardedBy; 30 import com.android.internal.app.procstats.AssociationState; 31 import com.android.internal.app.procstats.ProcessStats; 32 33 /** 34 * Represents a link between a content provider and client. 35 */ 36 public final class ContentProviderConnection extends Binder implements 37 OomAdjusterModernImpl.Connection { 38 public final ContentProviderRecord provider; 39 public final ProcessRecord client; 40 public final String clientPackage; 41 public AssociationState.SourceState association; 42 public final long createTime; 43 private Object mProcStatsLock; // Internal lock for accessing AssociationState 44 45 /** 46 * Internal lock that guards access to the two counters. 47 */ 48 private final Object mLock = new Object(); 49 @GuardedBy("mLock") 50 private int mStableCount; 51 @GuardedBy("mLock") 52 private int mUnstableCount; 53 // The client of this connection is currently waiting for the provider to appear. 54 // Protected by the provider lock. 55 public boolean waiting; 56 // The provider of this connection is now dead. 57 public boolean dead; 58 59 // The original user id when this connection was requested, it could be different from 60 // the client's user id because the client could request to access a content provider 61 // living in a different user if it has the permission. 62 @UserIdInt final int mExpectedUserId; 63 64 // For debugging. 65 private int mNumStableIncs; 66 private int mNumUnstableIncs; 67 ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client, String _clientPackage, @UserIdInt int _expectedUserId)68 public ContentProviderConnection(ContentProviderRecord _provider, ProcessRecord _client, 69 String _clientPackage, @UserIdInt int _expectedUserId) { 70 provider = _provider; 71 client = _client; 72 clientPackage = _clientPackage; 73 mExpectedUserId = _expectedUserId; 74 createTime = SystemClock.elapsedRealtime(); 75 } 76 77 @Override computeHostOomAdjLSP(OomAdjuster oomAdjuster, ProcessRecord host, ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, int oomAdjReason, int cachedAdj)78 public void computeHostOomAdjLSP(OomAdjuster oomAdjuster, ProcessRecord host, 79 ProcessRecord client, long now, ProcessRecord topApp, boolean doingAll, 80 int oomAdjReason, int cachedAdj) { 81 oomAdjuster.computeProviderHostOomAdjLSP(this, host, client, now, topApp, doingAll, false, 82 false, oomAdjReason, UNKNOWN_ADJ, false, false); 83 } 84 85 @Override canAffectCapabilities()86 public boolean canAffectCapabilities() { 87 return false; 88 } 89 90 startAssociationIfNeeded()91 public void startAssociationIfNeeded() { 92 // If we don't already have an active association, create one... but only if this 93 // is an association between two different processes. 94 if (ActivityManagerService.TRACK_PROCSTATS_ASSOCIATIONS 95 && association == null && provider.proc != null 96 && (provider.appInfo.uid != client.uid 97 || !provider.info.processName.equals(client.processName))) { 98 ProcessStats.ProcessStateHolder holder = provider.proc.getPkgList().get( 99 provider.name.getPackageName()); 100 if (holder == null) { 101 Slog.wtf(TAG_AM, "No package in referenced provider " 102 + provider.name.toShortString() + ": proc=" + provider.proc); 103 } else if (holder.pkg == null) { 104 Slog.wtf(TAG_AM, "Inactive holder in referenced provider " 105 + provider.name.toShortString() + ": proc=" + provider.proc); 106 } else { 107 mProcStatsLock = provider.proc.mService.mProcessStats.mLock; 108 synchronized (mProcStatsLock) { 109 association = holder.pkg.getAssociationStateLocked(holder.state, 110 provider.name.getClassName()).startSource(client.uid, 111 client.processName, clientPackage); 112 } 113 } 114 } 115 } 116 117 /** 118 * Track the given proc state change. 119 */ trackProcState(int procState, int seq)120 public void trackProcState(int procState, int seq) { 121 if (association != null) { 122 synchronized (mProcStatsLock) { 123 association.trackProcState(procState, seq, SystemClock.uptimeMillis()); 124 } 125 } 126 } 127 stopAssociation()128 public void stopAssociation() { 129 if (association != null) { 130 synchronized (mProcStatsLock) { 131 association.stop(); 132 } 133 association = null; 134 } 135 } 136 toString()137 public String toString() { 138 StringBuilder sb = new StringBuilder(128); 139 sb.append("ContentProviderConnection{"); 140 toShortString(sb); 141 sb.append('}'); 142 return sb.toString(); 143 } 144 toShortString()145 public String toShortString() { 146 StringBuilder sb = new StringBuilder(128); 147 toShortString(sb); 148 return sb.toString(); 149 } 150 toClientString()151 public String toClientString() { 152 StringBuilder sb = new StringBuilder(128); 153 toClientString(sb); 154 return sb.toString(); 155 } 156 toShortString(StringBuilder sb)157 public void toShortString(StringBuilder sb) { 158 sb.append(provider.toShortString()); 159 sb.append("->"); 160 toClientString(sb); 161 } 162 toClientString(StringBuilder sb)163 public void toClientString(StringBuilder sb) { 164 sb.append(client.toShortString()); 165 synchronized (mLock) { 166 sb.append(" s"); 167 sb.append(mStableCount); 168 sb.append("/"); 169 sb.append(mNumStableIncs); 170 sb.append(" u"); 171 sb.append(mUnstableCount); 172 sb.append("/"); 173 sb.append(mNumUnstableIncs); 174 } 175 if (waiting) { 176 sb.append(" WAITING"); 177 } 178 if (dead) { 179 sb.append(" DEAD"); 180 } 181 long nowReal = SystemClock.elapsedRealtime(); 182 sb.append(" "); 183 TimeUtils.formatDuration(nowReal-createTime, sb); 184 } 185 186 /** 187 * Initializes the reference counts. Either the stable or unstable count 188 * is set to 1; the other reference count is set to zero. 189 */ initializeCount(boolean stable)190 public void initializeCount(boolean stable) { 191 synchronized (mLock) { 192 if (stable) { 193 mStableCount = 1; 194 mNumStableIncs = 1; 195 mUnstableCount = 0; 196 mNumUnstableIncs = 0; 197 } else { 198 mStableCount = 0; 199 mNumStableIncs = 0; 200 mUnstableCount = 1; 201 mNumUnstableIncs = 1; 202 } 203 } 204 } 205 206 /** 207 * Increments the stable or unstable reference count and return the total 208 * number of references. 209 */ incrementCount(boolean stable)210 public int incrementCount(boolean stable) { 211 synchronized (mLock) { 212 if (DEBUG_PROVIDER) { 213 final ContentProviderRecord cpr = provider; 214 Slog.v(TAG_AM, 215 "Adding provider requested by " 216 + client.processName + " from process " 217 + cpr.info.processName + ": " + cpr.name.flattenToShortString() 218 + " scnt=" + mStableCount + " uscnt=" + mUnstableCount); 219 } 220 if (stable) { 221 mStableCount++; 222 mNumStableIncs++; 223 } else { 224 mUnstableCount++; 225 mNumUnstableIncs++; 226 } 227 return mStableCount + mUnstableCount; 228 } 229 } 230 231 /** 232 * Decrements either the stable or unstable count and return the total 233 * number of references. 234 */ decrementCount(boolean stable)235 public int decrementCount(boolean stable) { 236 synchronized (mLock) { 237 if (DEBUG_PROVIDER) { 238 final ContentProviderRecord cpr = provider; 239 Slog.v(TAG_AM, 240 "Removing provider requested by " 241 + client.processName + " from process " 242 + cpr.info.processName + ": " + cpr.name.flattenToShortString() 243 + " scnt=" + mStableCount + " uscnt=" + mUnstableCount); 244 } 245 if (stable) { 246 mStableCount--; 247 } else { 248 mUnstableCount--; 249 } 250 return mStableCount + mUnstableCount; 251 } 252 } 253 254 /** 255 * Adjusts the reference counts up or down (the inputs may be positive, 256 * zero, or negative. This method does not return a total count because 257 * a return is not needed for the current use case. 258 */ adjustCounts(int stableIncrement, int unstableIncrement)259 public void adjustCounts(int stableIncrement, int unstableIncrement) { 260 synchronized (mLock) { 261 if (stableIncrement > 0) { 262 mNumStableIncs += stableIncrement; 263 } 264 final int stable = mStableCount + stableIncrement; 265 if (stable < 0) { 266 throw new IllegalStateException("stableCount < 0: " + stable); 267 } 268 if (unstableIncrement > 0) { 269 mNumUnstableIncs += unstableIncrement; 270 } 271 final int unstable = mUnstableCount + unstableIncrement; 272 if (unstable < 0) { 273 throw new IllegalStateException("unstableCount < 0: " + unstable); 274 } 275 if ((stable + unstable) <= 0) { 276 throw new IllegalStateException("ref counts can't go to zero here: stable=" 277 + stable + " unstable=" + unstable); 278 } 279 mStableCount = stable; 280 mUnstableCount = unstable; 281 } 282 } 283 284 /** 285 * Returns the number of stable references. 286 */ stableCount()287 public int stableCount() { 288 synchronized (mLock) { 289 return mStableCount; 290 } 291 } 292 293 /** 294 * Returns the number of unstable references. 295 */ unstableCount()296 public int unstableCount() { 297 synchronized (mLock) { 298 return mUnstableCount; 299 } 300 } 301 302 /** 303 * Returns the total number of stable and unstable references. 304 */ totalRefCount()305 int totalRefCount() { 306 synchronized (mLock) { 307 return mStableCount + mUnstableCount; 308 } 309 } 310 } 311