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 
101     /**
102      * Track the given proc state change.
103      */
trackProcState(int procState, int seq)104     public void trackProcState(int procState, int seq) {
105         if (association != null) {
106             synchronized (mProcStatsLock) {
107                 association.trackProcState(procState, seq, SystemClock.uptimeMillis());
108             }
109         }
110     }
111 
stopAssociation()112     public void stopAssociation() {
113         if (association != null) {
114             synchronized (mProcStatsLock) {
115                 association.stop();
116             }
117             association = null;
118         }
119     }
120 
toString()121     public String toString() {
122         StringBuilder sb = new StringBuilder(128);
123         sb.append("ContentProviderConnection{");
124         toShortString(sb);
125         sb.append('}');
126         return sb.toString();
127     }
128 
toShortString()129     public String toShortString() {
130         StringBuilder sb = new StringBuilder(128);
131         toShortString(sb);
132         return sb.toString();
133     }
134 
toClientString()135     public String toClientString() {
136         StringBuilder sb = new StringBuilder(128);
137         toClientString(sb);
138         return sb.toString();
139     }
140 
toShortString(StringBuilder sb)141     public void toShortString(StringBuilder sb) {
142         sb.append(provider.toShortString());
143         sb.append("->");
144         toClientString(sb);
145     }
146 
toClientString(StringBuilder sb)147     public void toClientString(StringBuilder sb) {
148         sb.append(client.toShortString());
149         synchronized (mLock) {
150             sb.append(" s");
151             sb.append(mStableCount);
152             sb.append("/");
153             sb.append(mNumStableIncs);
154             sb.append(" u");
155             sb.append(mUnstableCount);
156             sb.append("/");
157             sb.append(mNumUnstableIncs);
158         }
159         if (waiting) {
160             sb.append(" WAITING");
161         }
162         if (dead) {
163             sb.append(" DEAD");
164         }
165         long nowReal = SystemClock.elapsedRealtime();
166         sb.append(" ");
167         TimeUtils.formatDuration(nowReal-createTime, sb);
168     }
169 
170     /**
171      * Initializes the reference counts.  Either the stable or unstable count
172      * is set to 1; the other reference count is set to zero.
173      */
initializeCount(boolean stable)174     public void initializeCount(boolean stable) {
175         synchronized (mLock) {
176             if (stable) {
177                 mStableCount = 1;
178                 mNumStableIncs = 1;
179                 mUnstableCount = 0;
180                 mNumUnstableIncs = 0;
181             } else {
182                 mStableCount = 0;
183                 mNumStableIncs = 0;
184                 mUnstableCount = 1;
185                 mNumUnstableIncs = 1;
186             }
187         }
188     }
189 
190     /**
191      * Increments the stable or unstable reference count and return the total
192      * number of references.
193      */
incrementCount(boolean stable)194     public int incrementCount(boolean stable) {
195         synchronized (mLock) {
196             if (DEBUG_PROVIDER) {
197                 final ContentProviderRecord cpr = provider;
198                 Slog.v(TAG_AM,
199                        "Adding provider requested by "
200                        + client.processName + " from process "
201                        + cpr.info.processName + ": " + cpr.name.flattenToShortString()
202                        + " scnt=" + mStableCount + " uscnt=" + mUnstableCount);
203             }
204             if (stable) {
205                 mStableCount++;
206                 mNumStableIncs++;
207             } else {
208                 mUnstableCount++;
209                 mNumUnstableIncs++;
210             }
211             return mStableCount + mUnstableCount;
212         }
213     }
214 
215     /**
216      * Decrements either the stable or unstable count and return the total
217      * number of references.
218      */
decrementCount(boolean stable)219     public int decrementCount(boolean stable) {
220         synchronized (mLock) {
221             if (DEBUG_PROVIDER) {
222                 final ContentProviderRecord cpr = provider;
223                 Slog.v(TAG_AM,
224                        "Removing provider requested by "
225                        + client.processName + " from process "
226                        + cpr.info.processName + ": " + cpr.name.flattenToShortString()
227                        + " scnt=" + mStableCount + " uscnt=" + mUnstableCount);
228             }
229             if (stable) {
230                 mStableCount--;
231             } else {
232                 mUnstableCount--;
233             }
234             return mStableCount + mUnstableCount;
235         }
236     }
237 
238     /**
239      * Adjusts the reference counts up or down (the inputs may be positive,
240      * zero, or negative.  This method does not return a total count because
241      * a return is not needed for the current use case.
242     */
adjustCounts(int stableIncrement, int unstableIncrement)243     public void adjustCounts(int stableIncrement, int unstableIncrement) {
244         synchronized (mLock) {
245             if (stableIncrement > 0) {
246                 mNumStableIncs += stableIncrement;
247             }
248             final int stable = mStableCount + stableIncrement;
249             if (stable < 0) {
250                 throw new IllegalStateException("stableCount < 0: " + stable);
251             }
252             if (unstableIncrement > 0) {
253                 mNumUnstableIncs += unstableIncrement;
254             }
255             final int unstable = mUnstableCount + unstableIncrement;
256             if (unstable < 0) {
257                 throw new IllegalStateException("unstableCount < 0: " + unstable);
258             }
259             if ((stable + unstable) <= 0) {
260                 throw new IllegalStateException("ref counts can't go to zero here: stable="
261                                                 + stable + " unstable=" + unstable);
262             }
263             mStableCount = stable;
264             mUnstableCount = unstable;
265         }
266     }
267 
268     /**
269      * Returns the number of stable references.
270      */
stableCount()271     public int stableCount() {
272         synchronized (mLock) {
273             return mStableCount;
274         }
275     }
276 
277     /**
278      * Returns the number of unstable references.
279      */
unstableCount()280     public int unstableCount() {
281         synchronized (mLock) {
282             return mUnstableCount;
283         }
284     }
285 
286     /**
287      * Returns the total number of stable and unstable references.
288      */
totalRefCount()289     int totalRefCount() {
290         synchronized (mLock) {
291             return mStableCount + mUnstableCount;
292         }
293     }
294 }
295