/*
* Copyright (C) 2006 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.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.display.DisplayManager;
import android.net.ConnectivityManager;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.AsyncResult;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.service.carrier.CarrierIdentifier;
import android.telephony.CellInfo;
import android.telephony.ModemActivityInfo;
import android.telephony.NeighboringCellInfo;
import android.telephony.PcoData;
import android.telephony.PhoneNumberUtils;
import android.telephony.RadioAccessFamily;
import android.telephony.Rlog;
import android.telephony.SignalStrength;
import android.telephony.SmsManager;
import android.telephony.SmsMessage;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyHistogram;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.SparseArray;
import android.view.Display;
import com.android.internal.telephony.TelephonyProto.SmsSession;
import com.android.internal.telephony.TelephonyProto.TelephonySettings;
import com.android.internal.telephony.cdma.CdmaCallWaitingNotification;
import com.android.internal.telephony.cdma.CdmaInformationRecords;
import com.android.internal.telephony.cdma.CdmaSmsBroadcastConfigInfo;
import com.android.internal.telephony.dataconnection.DataCallResponse;
import com.android.internal.telephony.dataconnection.DataProfile;
import com.android.internal.telephony.dataconnection.DcFailCause;
import com.android.internal.telephony.gsm.SmsBroadcastConfigInfo;
import com.android.internal.telephony.gsm.SsData;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.metrics.TelephonyMetrics;
import com.android.internal.telephony.uicc.IccCardApplicationStatus;
import com.android.internal.telephony.uicc.IccCardStatus;
import com.android.internal.telephony.uicc.IccIoResult;
import com.android.internal.telephony.uicc.IccRefreshResponse;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.SimPhoneBookAdnRecord;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.FileDescriptor;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
import static com.android.internal.telephony.RILConstants.*;
/**
* {@hide}
*/
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;
private Context mContext;
//***** Instance Variables
int mSerial;
int mRequest;
Message mResult;
Parcel mParcel;
RILRequest mNext;
int mWakeLockType;
// time in ms when RIL request was made
long mStartTimeMs;
/**
* 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.
*/
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();
}
rr.mSerial = sNextSerial.getAndIncrement();
rr.mRequest = request;
rr.mResult = result;
rr.mParcel = Parcel.obtain();
rr.mWakeLockType = RIL.INVALID_WAKELOCK;
rr.mStartTimeMs = SystemClock.elapsedRealtime();
if (result != null && result.getTarget() == null) {
throw new NullPointerException("Message target must not be null");
}
// first elements in any RIL Parcel
rr.mParcel.writeInt(request);
rr.mParcel.writeInt(rr.mSerial);
return rr;
}
/**
* Returns a RILRequest instance to the pool.
*
* Note: This should only be called once per use.
*/
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 random so that on recovery we probably don't mix old requests
// with new.
sNextSerial.set(sRandom.nextInt());
}
String
serialString() {
//Cheesy way to do %04d
StringBuilder sb = new StringBuilder(8);
String sn;
long adjustedSerial = (((long)mSerial) - Integer.MIN_VALUE)%10000;
sn = Long.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();
}
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();
}
if (mParcel != null) {
mParcel.recycle();
mParcel = null;
}
}
}
/**
* RIL implementation of the CommandsInterface.
*
* {@hide}
*/
public class RIL extends BaseCommands implements CommandsInterface {
static final String RILJ_LOG_TAG = "RILJ";
// Have a separate wakelock instance for Ack
static final String RILJ_ACK_WAKELOCK_NAME = "RILJ_ACK_WL";
static final boolean RILJ_LOGD = true;
static final boolean RILJ_LOGV = false; // STOPSHIP if true
static final int RADIO_SCREEN_UNSET = -1;
static final int RADIO_SCREEN_OFF = 0;
static final int RADIO_SCREEN_ON = 1;
static final int RIL_HISTOGRAM_BUCKET_COUNT = 5;
/**
* Wake lock timeout should be longer than the longest timeout in
* the vendor ril.
*/
private static final int DEFAULT_WAKE_LOCK_TIMEOUT_MS = 60000;
// Wake lock default timeout associated with ack
private static final int DEFAULT_ACK_WAKE_LOCK_TIMEOUT_MS = 200;
private static final int DEFAULT_BLOCKING_MESSAGE_RESPONSE_TIMEOUT_MS = 2000;
// Variables used to differentiate ack messages from request while calling clearWakeLock()
public static final int INVALID_WAKELOCK = -1;
public static final int FOR_WAKELOCK = 0;
public static final int FOR_ACK_WAKELOCK = 1;
//***** Instance Variables
LocalSocket mSocket;
HandlerThread mSenderThread;
RILSender mSender;
Thread mReceiverThread;
RILReceiver mReceiver;
Display mDefaultDisplay;
int mDefaultDisplayState = Display.STATE_UNKNOWN;
int mRadioScreenState = RADIO_SCREEN_UNSET;
boolean mIsDevicePlugged = false;
final WakeLock mWakeLock; // Wake lock associated with request/response
final WakeLock mAckWakeLock; // Wake lock associated with ack sent
final int mWakeLockTimeout; // Timeout associated with request/response
final int mAckWakeLockTimeout; // Timeout associated with ack sent
// The number of wakelock requests currently active. Don't release the lock
// until dec'd to 0
int mWakeLockCount;
// Variables used to identify releasing of WL on wakelock timeouts
volatile int mWlSequenceNum = 0;
volatile int mAckWlSequenceNum = 0;
SparseArray<RILRequest> mRequestList = new SparseArray<RILRequest>();
static SparseArray<TelephonyHistogram> mRilTimeHistograms = new
SparseArray<TelephonyHistogram>();
Object[] mLastNITZTimeInfo;
// When we are testing emergency calls
AtomicBoolean mTestingEmergencyCall = new AtomicBoolean(false);
protected Integer mInstanceId;
private List<String> mOldRilFeatures;
private TelephonyMetrics mMetrics = TelephonyMetrics.getInstance();
// Number of per-network elements expected in QUERY_AVAILABLE_NETWORKS's response.
// 4 elements is default, but many RILs actually return 5, making it impossible to
// divide the response array without prior knowledge of the number of elements.
protected int mQANElements = SystemProperties.getInt("ro.ril.telephony.mqanelements", 4);
//***** Events
static final int EVENT_SEND = 1;
static final int EVENT_WAKE_LOCK_TIMEOUT = 2;
static final int EVENT_SEND_ACK = 3;
static final int EVENT_ACK_WAKE_LOCK_TIMEOUT = 4;
static final int EVENT_BLOCKING_RESPONSE_TIMEOUT = 5;
//***** Constants
// match with constant in ril.cpp
static final int RIL_MAX_COMMAND_BYTES = (8 * 1024);
static final int RESPONSE_SOLICITED = 0;
static final int RESPONSE_UNSOLICITED = 1;
static final int RESPONSE_SOLICITED_ACK = 2;
static final int RESPONSE_SOLICITED_ACK_EXP = 3;
static final int RESPONSE_UNSOLICITED_ACK_EXP = 4;
static final String[] SOCKET_NAME_RIL = {
"rild", "rild2", "rild3"};
static final int SOCKET_OPEN_RETRY_MILLIS = 4 * 1000;
// The number of the required config values for broadcast SMS stored in the C struct
// RIL_CDMA_BroadcastServiceInfo
private static final int CDMA_BSI_NO_OF_INTS_STRUCT = 3;
private static final int CDMA_BROADCAST_SMS_NO_OF_SERVICE_CATEGORIES = 31;
private final DisplayManager.DisplayListener mDisplayListener =
new DisplayManager.DisplayListener() {
@Override
public void onDisplayAdded(int displayId) {
}
@Override
public void onDisplayRemoved(int displayId) {
}
@Override
public void onDisplayChanged(int displayId) {
if (displayId == Display.DEFAULT_DISPLAY) {
final int oldState = mDefaultDisplayState;
mDefaultDisplayState = mDefaultDisplay.getState();
if (mDefaultDisplayState != oldState) {
updateScreenState();
}
}
}
};
private final BroadcastReceiver mBatteryStateListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean oldState = mIsDevicePlugged;
// 0 means it's on battery
mIsDevicePlugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0;
if (mIsDevicePlugged != oldState) {
updateScreenState();
}
}
};
public static List<TelephonyHistogram> getTelephonyRILTimingHistograms() {
List<TelephonyHistogram> list;
synchronized (mRilTimeHistograms) {
list = new ArrayList<>(mRilTimeHistograms.size());
for (int i = 0; i < mRilTimeHistograms.size(); i++) {
TelephonyHistogram entry = new TelephonyHistogram(mRilTimeHistograms.valueAt(i));
list.add(entry);
}
}
return list;
}
class RILSender extends Handler implements Runnable {
public RILSender(Looper looper) {
super(looper);
}
// Only allocated once
byte[] dataLength = new byte[4];
//***** Runnable implementation
@Override
public void
run() {
//setup if needed
}
//***** Handler implementation
@Override public void
handleMessage(Message msg) {
RILRequest rr = (RILRequest)(msg.obj);
RILRequest req = null;
switch (msg.what) {
case EVENT_SEND:
case EVENT_SEND_ACK:
try {
LocalSocket s;
s = mSocket;
if (s == null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
decrementWakeLock(rr);
rr.release();
return;
}
// Acks should not be stored in list before sending
if (msg.what != EVENT_SEND_ACK) {
synchronized (mRequestList) {
rr.mStartTimeMs = SystemClock.elapsedRealtime();
mRequestList.append(rr.mSerial, rr);
}
}
byte[] data;
data = rr.mParcel.marshall();
rr.mParcel.recycle();
rr.mParcel = null;
if (data.length > RIL_MAX_COMMAND_BYTES) {
throw new RuntimeException(
"Parcel larger than max bytes allowed! "
+ data.length);
}
// parcel length in big endian
dataLength[0] = dataLength[1] = 0;
dataLength[2] = (byte)((data.length >> 8) & 0xff);
dataLength[3] = (byte)((data.length) & 0xff);
//Rlog.v(RILJ_LOG_TAG, "writing packet: " + data.length + " bytes");
s.getOutputStream().write(dataLength);
s.getOutputStream().write(data);
if (msg.what == EVENT_SEND_ACK) {
rr.release();
return;
}
} catch (IOException ex) {
Rlog.e(RILJ_LOG_TAG, "IOException", ex);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null) {
rr.onError(RADIO_NOT_AVAILABLE, null);
decrementWakeLock(rr);
rr.release();
return;
}
} catch (RuntimeException exc) {
Rlog.e(RILJ_LOG_TAG, "Uncaught exception ", exc);
req = findAndRemoveRequestFromList(rr.mSerial);
// make sure this request has not already been handled,
// eg, if RILReceiver cleared the list.
if (req != null) {
rr.onError(GENERIC_FAILURE, null);
decrementWakeLock(rr);
rr.release();
return;
}
}
break;
case EVENT_WAKE_LOCK_TIMEOUT:
// Haven't heard back from the last request. Assume we're
// not getting a response and release the wake lock.
// The timer of WAKE_LOCK_TIMEOUT is reset with each
// new send request. So when WAKE_LOCK_TIMEOUT occurs
// all requests in mRequestList already waited at
// least DEFAULT_WAKE_LOCK_TIMEOUT_MS but no response.
//
// Note: Keep mRequestList so that delayed response
// can still be handled when response finally comes.
synchronized (mRequestList) {
if (msg.arg1 == mWlSequenceNum && clearWakeLock(FOR_WAKELOCK)) {
if (RILJ_LOGD) {
int count = mRequestList.size();
Rlog.d(RILJ_LOG_TAG, "WAKE_LOCK_TIMEOUT " +
" mRequestList=" + count);
for (int i = 0; i < count; i++) {
rr = mRequestList.valueAt(i);
Rlog.d(RILJ_LOG_TAG, i + ": [" + rr.mSerial + "] "
+ requestToString(rr.mRequest));
}
}
}
}
break;
case EVENT_ACK_WAKE_LOCK_TIMEOUT:
if (msg.arg1 == mAckWlSequenceNum && clearWakeLock(FOR_ACK_WAKELOCK)) {
if (RILJ_LOGV) {
Rlog.d(RILJ_LOG_TAG, "ACK_WAKE_LOCK_TIMEOUT");
}
}
break;
case EVENT_BLOCKING_RESPONSE_TIMEOUT:
int serial = msg.arg1;
rr = findAndRemoveRequestFromList(serial);
// If the request has already been processed, do nothing
if(rr == null) {
break;
}
//build a response if expected
if (rr.mResult != null) {
Object timeoutResponse = getResponseForTimedOutRILRequest(rr);
AsyncResult.forMessage( rr.mResult, timeoutResponse, null);
rr.mResult.sendToTarget();
mMetrics.writeOnRilTimeoutResponse(mInstanceId, rr.mSerial, rr.mRequest);
}
decrementWakeLock(rr);
rr.release();
break;
}
}
}
/**
* In order to prevent calls to Telephony from waiting indefinitely
* low-latency blocking calls will eventually time out. In the event of
* a timeout, this function generates a response that is returned to the
* higher layers to unblock the call. This is in lieu of a meaningful
* response.
* @param rr The RIL Request that has timed out.
* @return A default object, such as the one generated by a normal response
* that is returned to the higher layers.
**/
private static Object getResponseForTimedOutRILRequest(RILRequest rr) {
if (rr == null ) return null;
Object timeoutResponse = null;
switch(rr.mRequest) {
case RIL_REQUEST_GET_ACTIVITY_INFO:
timeoutResponse = new ModemActivityInfo(
0, 0, 0, new int [ModemActivityInfo.TX_POWER_LEVELS], 0, 0);
break;
};
return timeoutResponse;
}
/**
* Reads in a single RIL message off the wire. A RIL message consists
* of a 4-byte little-endian length and a subsequent series of bytes.
* The final message (length header omitted) is read into
* <code>buffer</code> and the length of the final message (less header)
* is returned. A return value of -1 indicates end-of-stream.
*
* @param is non-null; Stream to read from
* @param buffer Buffer to fill in. Must be as large as maximum
* message size, or an ArrayOutOfBounds exception will be thrown.
* @return Length of message less header, or -1 on end of stream.
* @throws IOException
*/
private static int readRilMessage(InputStream is, byte[] buffer)
throws IOException {
int countRead;
int offset;
int remaining;
int messageLength;
// First, read in the length of the message
offset = 0;
remaining = 4;
do {
countRead = is.read(buffer, offset, remaining);
if (countRead < 0 ) {
Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message length");
return -1;
}
offset += countRead;
remaining -= countRead;
} while (remaining > 0);
messageLength = ((buffer[0] & 0xff) << 24)
| ((buffer[1] & 0xff) << 16)
| ((buffer[2] & 0xff) << 8)
| (buffer[3] & 0xff);
// Then, re-use the buffer and read in the message itself
offset = 0;
remaining = messageLength;
do {
countRead = is.read(buffer, offset, remaining);
if (countRead < 0 ) {
Rlog.e(RILJ_LOG_TAG, "Hit EOS reading message. messageLength=" + messageLength
+ " remaining=" + remaining);
return -1;
}
offset += countRead;
remaining -= countRead;
} while (remaining > 0);
return messageLength
从系统底层伪造 IMEI
最新推荐文章于 2024-06-29 15:16:07 发布