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