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