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