Android恢复出厂设置保存文件标志位到 persist 分区

工作过程时常遇到恢复出厂设置需要保留之前设置的某些标志位的问题,如某些关闭4G能力的手机,实际上只是从网络模式上做了限制,我们可以通过暗码来控制其开关,同时又希望恢复出厂设置能够保留之前设置状态。这就可以通过在 persist 分区新建或删除标识文件来实现。

1、Android 暗码的注册与监听

packages/services/Telephony/AndroidManifest.xml

        
            
                
                
            
            
                
                
            
        


2、添加监听处理 Receiver

packages/services/Telephony/src/com/fly/phone/LteSupportChangeReceiver.java

package com.fly.phone;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.util.Log;


import com.android.ims.ImsManager;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.RILConstants;
import com.android.phone.R;

import java.util.List;
import java.io.File;
import java.io.IOException;


/**
 * deal with the changes of whether support 4G or not
 */
public class LteSupportChangeReceiver extends BroadcastReceiver {
    private final static String TAG = "LteSupportChangeReceiver";

    private Context mContext;

    private static final String SECRET_CODE_ACTION = "android.provider.Telephony.SECRET_CODE";

    private static final String SECTET_CODE_ENABLE_4G = "5744";
    private static final String SECTET_CODE_DISABLE_4G = "4244";
    private static final String FILE_NAME="/persist/tele/4G.FLG";

    private static final int PREF_NETWORK_MODE_LTE_ON =
            RILConstants.NETWORK_MODE_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA;
    private static final int PREF_NETWORK_MODE_LTE_OFF =
            RILConstants.NETWORK_MODE_TD_SCDMA_GSM_WCDMA_CDMA_EVDO;

    @Override
    public void onReceive(Context context, Intent intent) {

        String action = intent.getAction();
        mContext = context;

        if (SECRET_CODE_ACTION.equals(action)) {
            String host = intent.getData() != null ? intent.getData().getHost(): null;
            Log.d(TAG, "onReceive:  SECRET_CODE_ACTION -- HOST  = " + host);

            if (SECTET_CODE_ENABLE_4G.equals(host)) {
                try {
                    File file = new File(FILE_NAME);
                    if (!file.exists()) {
                        file.createNewFile();
                        Log.d(TAG, "onReceive: enable 4G, create 4G.FLG");
                    } else {
                        Log.d(TAG, "onReceive: enable 4G, 4G.FLG has existed");
                    }
                } catch (IOException e) {
                    Log.d(TAG, "onReceive: IOException"+e);
                }

                changePreferredNetworkMode(PREF_NETWORK_MODE_LTE_ON);

            } else {
                File file = new File(FILE_NAME);
                if (file.exists()) {
                    file.delete();
                    Log.d(TAG, "onReceive: disable 4G, delete 4G.FLG");
                } else {
                    Log.d(TAG, "onReceive: disable 4G, No 4G.FLG");
                }

                changePreferredNetworkMode(PREF_NETWORK_MODE_LTE_OFF);
            }
        }
    }

    private void changePreferredNetworkMode(int nwMode) {
        int defaultDataSubId = SubscriptionManager.getDefaultDataSubId();
        int phoneId = SubscriptionManager.getPhoneId(defaultDataSubId);
        Phone dataPhone = PhoneFactory.getPhone(phoneId);
        Log.d(TAG, "defaultDataSubId = " + defaultDataSubId + ", phoneId = " + phoneId);
        if (dataPhone == null) {
            Log.d(TAG, "dataPhone is null, get default phone !");
            dataPhone = PhoneFactory.getDefaultPhone();
        }

        List subInfoList = SubscriptionManager.from(mContext).getAllSubscriptionInfoList();
        Log.d(TAG, "changePreferredNetworkMode, allSubInfoList  = " + subInfoList);

        int subInfoCount = subInfoList != null ? subInfoList.size() : 0;
        int oldNwMode;
        boolean changeModemNetworkType;
        boolean isLteNetworkType;

        for (int i = 0; i < subInfoCount; i++) {
            int subId = subInfoList.get(i).getSubscriptionId();

            oldNwMode  = android.provider.Settings.Global.getInt(
                    mContext.getContentResolver(),
                    Settings.Global.PREFERRED_NETWORK_MODE + subId, -1);

            changeModemNetworkType = false;
            isLteNetworkType = PhoneFactory . isLteNetworkType(oldNwMode);

            if (isLteNetworkType && nwMode == PREF_NETWORK_MODE_LTE_OFF) {
                changeModemNetworkType = true;
                Log.d(TAG, "changePreferredNetworkMode: nwMode = " + nwMode + ", subId = " + subId);
            }
            if (isNeedChangeToLte(oldNwMode) && nwMode == PREF_NETWORK_MODE_LTE_ON) {
                changeModemNetworkType = true;
                Log.d(TAG, "changePreferredNetworkMode: nwMode = " + nwMode + ", subId = " + subId);
            }

            // we assume that it is impossible that saved network type is not same with modem type.
            if (changeModemNetworkType && subId == defaultDataSubId) {
                Log.d(TAG, "changePreferredNetworkMode: set data phone nwMode to " + nwMode);

                TelephonyManager.putIntAtIndex(
                        mContext.getContentResolver(),
                        Settings.Global.PREFERRED_NETWORK_MODE, dataPhone.getPhoneId(), nwMode);

                dataPhone.setPreferredNetworkType(nwMode, null);

                // we need close volte for non lte support mode. But we will not open it if ltet
                // is enabled. Let user to decided.
                if (nwMode != PREF_NETWORK_MODE_LTE_ON) {
                    ImsManager.setEnhanced4gLteModeSetting(mContext, false);
                }
            }
        }

        // we need make sure network type for another phone is also changed to avoid problems.
        if (TelephonyManager.from(mContext).getPhoneCount() > 1) {
            int anotherPhoneId = dataPhone.getPhoneId() == 0 ? 1 : 0;

            TelephonyManager.putIntAtIndex(
                    mContext.getContentResolver(),
                    Settings.Global.PREFERRED_NETWORK_MODE, anotherPhoneId, nwMode);
        }
    }

    private boolean isNeedChangeToLte(int networkType) {
        if (networkType == RILConstants.NETWORK_MODE_GSM_ONLY
                || networkType == RILConstants.NETWORK_MODE_CDMA_NO_EVDO
                || networkType == RILConstants.NETWORK_MODE_EVDO_NO_CDMA
                || networkType == RILConstants.NETWORK_MODE_WCDMA_ONLY
                || networkType == RILConstants.NETWORK_MODE_TD_SCDMA_ONLY) {
            return false;
        } else {
            return true;
        }
    }
 }


3、关于selinux权限 和 用户权限组 修改

device/feixiang/sepolicy/radio.te

allow radio persist_file:dir {search getattr read write add_name remove_name};
allow radio persist_file:file {getattr read write create open unlink};

system/core/rootdir/init.rc

mkdir /persist/tele 0770 radio system    // 修改用户权限组 


PS: root 权限手机手动关闭 selinux权限 用于调试 (重启恢复)

$ adb shell setenforce 0

$ adb shell getenforce // 查看是否生效


4、标志文件使用

frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java

    public static boolean isNonLteMode(Context context) {
            File file = new File("/persist/tele/4G.FLG");
            if (!file.exists()) {
                Rlog.d(LOG_TAG,"4G.FLG exists, return true");              
                return true;
            } else {
                Rlog.d(LOG_TAG,"4G.FLG not exist, return false");
                return false;
            }
     }

   public static boolean isLteNetworkType(int networkType) {

        if (networkType == RILConstants.NETWORK_MODE_TD_SCDMA_LTE_CDMA_EVDO_GSM_WCDMA
                || networkType == RILConstants.NETWORK_MODE_LTE_GSM_WCDMA
                || networkType == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA
                || networkType == RILConstants.NETWORK_MODE_LTE_ONLY
                || networkType == RILConstants.NETWORK_MODE_LTE_WCDMA
                || networkType == RILConstants.NETWORK_MODE_TD_SCDMA_LTE
                || networkType == RILConstants.NETWORK_MODE_TD_SCDMA_GSM_LTE
                || networkType == RILConstants.NETWORK_MODE_TD_SCDMA_WCDMA_LTE
                || networkType == RILConstants.NETWORK_MODE_TD_SCDMA_GSM_WCDMA_LTE
                || networkType == RILConstants.NETWORK_MODE_LTE_CDMA_EVDO) {
            return true;
        } else {
            return false;
        }
    }

frameworks/opt/telephony/src/java/com/android/internal/telephony/RIL.java

    @Override
    public void setPreferredNetworkType(int networkType , Message response) {
        if (PhoneFactory.isNonLteMode(mContext)
                && PhoneFactory.isLteNetworkType(networkType)) {
            riljLog("Non LTE mode, force change network type to non lte mode 21");
            networkType = NETWORK_MODE_TD_SCDMA_GSM_WCDMA_CDMA_EVDO;
        }

        RILRequest rr = RILRequest.obtain(
                RILConstants.RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE, response);

        rr.mParcel.writeInt(1);
        rr.mParcel.writeInt(networkType);

        mPreferredNetworkType = networkType;

        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
                + " : " + networkType);

        send(rr);
    }



你可能感兴趣的:(那些事儿)