| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.internal.telephony; |
| |
| import android.annotation.UnsupportedAppUsage; |
| import android.os.AsyncResult; |
| import android.os.Message; |
| import android.os.SystemClock; |
| import android.os.WorkSource; |
| import android.os.WorkSource.WorkChain; |
| import android.telephony.Rlog; |
| |
| import java.util.ArrayList; |
| import java.util.Random; |
| import java.util.concurrent.atomic.AtomicInteger; |
| |
| /** |
| * {@hide} |
| */ |
| |
| public class RILRequest { |
| static final String LOG_TAG = "RilRequest"; |
| |
| //***** Class Variables |
| static Random sRandom = new Random(); |
| static AtomicInteger sNextSerial = new AtomicInteger(0); |
| private static Object sPoolSync = new Object(); |
| private static RILRequest sPool = null; |
| private static int sPoolSize = 0; |
| private static final int MAX_POOL_SIZE = 4; |
| |
| //***** Instance Variables |
| @UnsupportedAppUsage |
| int mSerial; |
| @UnsupportedAppUsage |
| int mRequest; |
| @UnsupportedAppUsage |
| Message mResult; |
| RILRequest mNext; |
| int mWakeLockType; |
| WorkSource mWorkSource; |
| String mClientId; |
| // time in ms when RIL request was made |
| long mStartTimeMs; |
| |
| public int getSerial() { |
| return mSerial; |
| } |
| |
| public int getRequest() { |
| return mRequest; |
| } |
| |
| public Message getResult() { |
| return mResult; |
| } |
| |
| /** |
| * Retrieves a new RILRequest instance from the pool. |
| * |
| * @param request RIL_REQUEST_* |
| * @param result sent when operation completes |
| * @return a RILRequest instance from the pool. |
| */ |
| @UnsupportedAppUsage |
| private static RILRequest obtain(int request, Message result) { |
| RILRequest rr = null; |
| |
| synchronized (sPoolSync) { |
| if (sPool != null) { |
| rr = sPool; |
| sPool = rr.mNext; |
| rr.mNext = null; |
| sPoolSize--; |
| } |
| } |
| |
| if (rr == null) { |
| rr = new RILRequest(); |
| } |
| |
| // Increment serial number. Wrap to 0 when reaching Integer.MAX_VALUE. |
| rr.mSerial = sNextSerial.getAndUpdate(n -> ((n + 1) % Integer.MAX_VALUE)); |
| |
| rr.mRequest = request; |
| rr.mResult = result; |
| |
| rr.mWakeLockType = RIL.INVALID_WAKELOCK; |
| rr.mWorkSource = null; |
| rr.mStartTimeMs = SystemClock.elapsedRealtime(); |
| if (result != null && result.getTarget() == null) { |
| throw new NullPointerException("Message target must not be null"); |
| } |
| |
| return rr; |
| } |
| |
| |
| /** |
| * Retrieves a new RILRequest instance from the pool and sets the clientId |
| * |
| * @param request RIL_REQUEST_* |
| * @param result sent when operation completes |
| * @param workSource WorkSource to track the client |
| * @return a RILRequest instance from the pool. |
| */ |
| // @VisibleForTesting |
| public static RILRequest obtain(int request, Message result, WorkSource workSource) { |
| RILRequest rr = obtain(request, result); |
| |
| if (workSource != null) { |
| rr.mWorkSource = workSource; |
| rr.mClientId = rr.getWorkSourceClientId(); |
| } else { |
| Rlog.e(LOG_TAG, "null workSource " + request); |
| } |
| |
| return rr; |
| } |
| |
| /** |
| * Generate a String client ID from the WorkSource. |
| */ |
| // @VisibleForTesting |
| public String getWorkSourceClientId() { |
| if (mWorkSource == null || mWorkSource.isEmpty()) { |
| return null; |
| } |
| |
| if (mWorkSource.size() > 0) { |
| return mWorkSource.get(0) + ":" + mWorkSource.getName(0); |
| } |
| |
| final ArrayList<WorkChain> workChains = mWorkSource.getWorkChains(); |
| if (workChains != null && !workChains.isEmpty()) { |
| final WorkChain workChain = workChains.get(0); |
| return workChain.getAttributionUid() + ":" + workChain.getTags()[0]; |
| } |
| |
| return null; |
| } |
| |
| /** |
| * Returns a RILRequest instance to the pool. |
| * |
| * Note: This should only be called once per use. |
| */ |
| @UnsupportedAppUsage |
| void release() { |
| synchronized (sPoolSync) { |
| if (sPoolSize < MAX_POOL_SIZE) { |
| mNext = sPool; |
| sPool = this; |
| sPoolSize++; |
| mResult = null; |
| if (mWakeLockType != RIL.INVALID_WAKELOCK) { |
| //This is OK for some wakelock types and not others |
| if (mWakeLockType == RIL.FOR_WAKELOCK) { |
| Rlog.e(LOG_TAG, "RILRequest releasing with held wake lock: " |
| + serialString()); |
| } |
| } |
| } |
| } |
| } |
| |
| private RILRequest() { |
| } |
| |
| static void resetSerial() { |
| // Use a non-negative random number so that on recovery we probably don't mix old requests |
| // with new. |
| sNextSerial.set(sRandom.nextInt(Integer.MAX_VALUE)); |
| } |
| |
| @UnsupportedAppUsage |
| String serialString() { |
| //Cheesy way to do %04d |
| StringBuilder sb = new StringBuilder(8); |
| String sn; |
| |
| // Truncate mSerial to a number with maximum 4 digits. |
| int adjustedSerial = mSerial % 10000; |
| sn = Integer.toString(adjustedSerial); |
| |
| //sb.append("J["); |
| sb.append('['); |
| for (int i = 0, s = sn.length(); i < 4 - s; i++) { |
| sb.append('0'); |
| } |
| |
| sb.append(sn); |
| sb.append(']'); |
| return sb.toString(); |
| } |
| |
| @UnsupportedAppUsage |
| void onError(int error, Object ret) { |
| CommandException ex; |
| |
| ex = CommandException.fromRilErrno(error); |
| |
| if (RIL.RILJ_LOGD) { |
| Rlog.d(LOG_TAG, serialString() + "< " |
| + RIL.requestToString(mRequest) |
| + " error: " + ex + " ret=" + RIL.retToString(mRequest, ret)); |
| } |
| |
| if (mResult != null) { |
| AsyncResult.forMessage(mResult, ret, ex); |
| mResult.sendToTarget(); |
| } |
| } |
| } |