1 /* 2 * Copyright (C) 2017 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.internal.telephony; 18 19 import android.annotation.UnsupportedAppUsage; 20 import android.os.AsyncResult; 21 import android.os.Message; 22 import android.os.SystemClock; 23 import android.os.WorkSource; 24 import android.os.WorkSource.WorkChain; 25 import android.telephony.Rlog; 26 27 import java.util.ArrayList; 28 import java.util.Random; 29 import java.util.concurrent.atomic.AtomicInteger; 30 31 /** 32 * {@hide} 33 */ 34 35 public class RILRequest { 36 static final String LOG_TAG = "RilRequest"; 37 38 //***** Class Variables 39 static Random sRandom = new Random(); 40 static AtomicInteger sNextSerial = new AtomicInteger(0); 41 private static Object sPoolSync = new Object(); 42 private static RILRequest sPool = null; 43 private static int sPoolSize = 0; 44 private static final int MAX_POOL_SIZE = 4; 45 46 //***** Instance Variables 47 @UnsupportedAppUsage 48 int mSerial; 49 @UnsupportedAppUsage 50 int mRequest; 51 @UnsupportedAppUsage 52 Message mResult; 53 RILRequest mNext; 54 int mWakeLockType; 55 WorkSource mWorkSource; 56 String mClientId; 57 // time in ms when RIL request was made 58 long mStartTimeMs; 59 getSerial()60 public int getSerial() { 61 return mSerial; 62 } 63 getRequest()64 public int getRequest() { 65 return mRequest; 66 } 67 getResult()68 public Message getResult() { 69 return mResult; 70 } 71 72 /** 73 * Retrieves a new RILRequest instance from the pool. 74 * 75 * @param request RIL_REQUEST_* 76 * @param result sent when operation completes 77 * @return a RILRequest instance from the pool. 78 */ 79 @UnsupportedAppUsage obtain(int request, Message result)80 private static RILRequest obtain(int request, Message result) { 81 RILRequest rr = null; 82 83 synchronized (sPoolSync) { 84 if (sPool != null) { 85 rr = sPool; 86 sPool = rr.mNext; 87 rr.mNext = null; 88 sPoolSize--; 89 } 90 } 91 92 if (rr == null) { 93 rr = new RILRequest(); 94 } 95 96 // Increment serial number. Wrap to 0 when reaching Integer.MAX_VALUE. 97 rr.mSerial = sNextSerial.getAndUpdate(n -> ((n + 1) % Integer.MAX_VALUE)); 98 99 rr.mRequest = request; 100 rr.mResult = result; 101 102 rr.mWakeLockType = RIL.INVALID_WAKELOCK; 103 rr.mWorkSource = null; 104 rr.mStartTimeMs = SystemClock.elapsedRealtime(); 105 if (result != null && result.getTarget() == null) { 106 throw new NullPointerException("Message target must not be null"); 107 } 108 109 return rr; 110 } 111 112 113 /** 114 * Retrieves a new RILRequest instance from the pool and sets the clientId 115 * 116 * @param request RIL_REQUEST_* 117 * @param result sent when operation completes 118 * @param workSource WorkSource to track the client 119 * @return a RILRequest instance from the pool. 120 */ 121 // @VisibleForTesting obtain(int request, Message result, WorkSource workSource)122 public static RILRequest obtain(int request, Message result, WorkSource workSource) { 123 RILRequest rr = obtain(request, result); 124 125 if (workSource != null) { 126 rr.mWorkSource = workSource; 127 rr.mClientId = rr.getWorkSourceClientId(); 128 } else { 129 Rlog.e(LOG_TAG, "null workSource " + request); 130 } 131 132 return rr; 133 } 134 135 /** 136 * Generate a String client ID from the WorkSource. 137 */ 138 // @VisibleForTesting getWorkSourceClientId()139 public String getWorkSourceClientId() { 140 if (mWorkSource == null || mWorkSource.isEmpty()) { 141 return null; 142 } 143 144 if (mWorkSource.size() > 0) { 145 return mWorkSource.get(0) + ":" + mWorkSource.getName(0); 146 } 147 148 final ArrayList<WorkChain> workChains = mWorkSource.getWorkChains(); 149 if (workChains != null && !workChains.isEmpty()) { 150 final WorkChain workChain = workChains.get(0); 151 return workChain.getAttributionUid() + ":" + workChain.getTags()[0]; 152 } 153 154 return null; 155 } 156 157 /** 158 * Returns a RILRequest instance to the pool. 159 * 160 * Note: This should only be called once per use. 161 */ 162 @UnsupportedAppUsage release()163 void release() { 164 synchronized (sPoolSync) { 165 if (sPoolSize < MAX_POOL_SIZE) { 166 mNext = sPool; 167 sPool = this; 168 sPoolSize++; 169 mResult = null; 170 if (mWakeLockType != RIL.INVALID_WAKELOCK) { 171 //This is OK for some wakelock types and not others 172 if (mWakeLockType == RIL.FOR_WAKELOCK) { 173 Rlog.e(LOG_TAG, "RILRequest releasing with held wake lock: " 174 + serialString()); 175 } 176 } 177 } 178 } 179 } 180 RILRequest()181 private RILRequest() { 182 } 183 resetSerial()184 static void resetSerial() { 185 // Use a non-negative random number so that on recovery we probably don't mix old requests 186 // with new. 187 sNextSerial.set(sRandom.nextInt(Integer.MAX_VALUE)); 188 } 189 190 @UnsupportedAppUsage serialString()191 String serialString() { 192 //Cheesy way to do %04d 193 StringBuilder sb = new StringBuilder(8); 194 String sn; 195 196 // Truncate mSerial to a number with maximum 4 digits. 197 int adjustedSerial = mSerial % 10000; 198 sn = Integer.toString(adjustedSerial); 199 200 //sb.append("J["); 201 sb.append('['); 202 for (int i = 0, s = sn.length(); i < 4 - s; i++) { 203 sb.append('0'); 204 } 205 206 sb.append(sn); 207 sb.append(']'); 208 return sb.toString(); 209 } 210 211 @UnsupportedAppUsage onError(int error, Object ret)212 void onError(int error, Object ret) { 213 CommandException ex; 214 215 ex = CommandException.fromRilErrno(error); 216 217 if (RIL.RILJ_LOGD) { 218 Rlog.d(LOG_TAG, serialString() + "< " 219 + RIL.requestToString(mRequest) 220 + " error: " + ex + " ret=" + RIL.retToString(mRequest, ret)); 221 } 222 223 if (mResult != null) { 224 AsyncResult.forMessage(mResult, ret, ex); 225 mResult.sendToTarget(); 226 } 227 } 228 } 229