Android 如何对/dev/log路径进行读写

/dev/log这个路径直接操作是无法进行读写的,所以我在framework层对这个路径进行关联,然后三方应用就是对这个路径进行读写了.闲话少说,直接上代码.首先自定义service,这个流程前面文章有所介绍,这里我就只贴出service相关的代码,

首先是frameworks/base/core/java/android/app/customized/ICustomizedService.aidl文件

package android.app.customized;
 
interface ICustomizedService{
    void shutDown ();
    void setCustomlog(String log , boolean isTest);
    void setCustomSerialNumber();
    String getCustomBuildNumber();
}

然后是frameworks/base/core/java/android/app/customized/CustomizedManager.java文件

package android.app.customized;
 
import android.util.Log;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.RemoteException;
import android.provider.Settings;
import java.io.IOException;
import android.os.ServiceManager;
import android.os.IBinder;
import java.util.List;
import android.app.ActivityManager;
import android.graphics.Bitmap;
 
 
public class CustomizedManager{
    private static final String TAG="CustomizedManager";
    private static final boolean DBG=true;
    
    private static ICustomizedService mService;
    private final Context mContext;
    /* device|time|which1~6|result|notes */
    public static String UNLOCK = "001";
    public static String M_TIME = "002";
    public static String REBOOT = "003";
    public static String UPGRADE = "004";
    public static String INSTALL = "005";
    public static String UNINSTALL = "006";
    public static String DEF_DISCRIBE = "NONE";
    public static String DEF_SPLIT = "|";
    public static String RESULT_NO = "0";
    public static String RESULT_YES = "1";
 
 
    public CustomizedManager(Context context){
        mContext = context;
        mService = ICustomizedService.Stub.asInterface(
                ServiceManager.getService("customized"));
    }
    private static ICustomizedService getService(){
        if (mService != null) {
            return mService;
        }
        
        IBinder b = ServiceManager.getService("customized");
        mService = ICustomizedService.Stub.asInterface(b);
        return mService;
    }
 
    public void shutDown () {
       ICustomizedService service = getService();
        try {
            service.shutDown();
        } catch (Exception e) {}
    }

    public String getCustomBuildNumber(){
        try {
           return getService().getCustomBuildNumber();
        } catch (Exception e){}
	return "CUSTOMGJDW1";
    }

    public void setCustomSerialNumber() {
        try {
           getService().setCustomSerialNumber();
        } catch (Exception e) {}
    }

    public void setCustomlog(String log , boolean isTest) {
	    Log.d("lei","CustomizedManager setCustomlog");
        try {
           getService().setCustomlog(log ,isTest);
        } catch (Exception e) {}
    }
 
}

最后是frameworks/base/services/core/java/com/android/server/customized/CustomizedService.java

package com.android.server.customized;
 
import android.os.IBinder;
import android.os.ServiceManager;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.app.customized.ICustomizedService;
import android.content.BroadcastReceiver;
 
 
 
public class CustomizedService extends ICustomizedService.Stub {
    private static final String TAG = "CustomizedService ";
    private Context mContext;
 
    public static class Lifecycle extends SystemService {
        private CustomizedService mService;
 
       public Lifecycle(Context context) {
            super(context);
        }
 
        @Override
        public void onStart() {
            mService = new CustomizedService (getContext());
            publishBinderService(Context.CUSTOMIZED, mService);
        }
 
       @Override
        public void onBootPhase(int phase) {
        }
 
        @Override
        public void onUnlockUser(int userHandle) {
        }
    }
 
    public CustomizedService (Context context) {
       mContext = context;
   }
 
    /**
     *  1 add interface shutDown()
     */ 
    public void shutDown () {
       sentControl("custom_shutdown", "null",true);
    }
 
    private void sentControl(String action, String key, boolean iscontrol) {
       long jh = Binder.clearCallingIdentity();
       Intent i = new Intent();
       i.setAction(action);
       if (iscontrol) {
           i.putExtra(key, true);
       } else {
           i.putExtra(key, false);
       }
       mContext.sendBroadcast(i);
       sentControl (action,iscontrol);
       Binder.restoreCallingIdentity(jh);
    }
 
    private void sentControl(String action, boolean iscontrol) {
       long jh = Binder.clearCallingIdentity();
       int key;
       if (iscontrol) {
           key = 0;
       } else {
           key = 1;
      }
       Log.i ("custom",",action "+ action + ";   key"+key);   
       Settings.Secure.putInt(mContext.getContentResolver(),action,key);
      Binder.restoreCallingIdentity(jh);
  }

    public String getCustomBuildNumber(){
        Binder.clearCallingIdentity();
        try {
            return android.os.SystemProperties.get("ro.lenovosn2","unknown");
        } catch (Exception e) {
            return "CUSTOMGJDW1";
        } finally{
            Binder.restoreCallingIdentity(DUMP_TRANSACTION);
        }
    }

    public void setCustomSerialNumber() {
        Binder.clearCallingIdentity();
        try {
            new CustomSetSn();
        } catch (Exception e) {
            Log.d("lei","setCustomSerialNumber Exception" + e);
        }
        Binder.restoreCallingIdentity(DUMP_TRANSACTION);
    }

    public void setCustomlog(String log , boolean isTest) {
	Log.d("lei","CustomizedService = " + log +" ; isTest="+isTest);
        Binder.clearCallingIdentity();
        WatchCat.getInstance(mContext).customPerpetual(log,isTest);
        Binder.restoreCallingIdentity(DUMP_TRANSACTION);
    }
 
 
}
 

以上是service的三个文件,下面的修改才是真正的重头戏

1,首先新建frameworks/base/services/core/java/com/android/server/customized/CustomSetSn.java文件,这个文件是读取系统NV值.本质是通过读取NV值获取系统SN.

package com.android.server.customized;

import android.os.Build;
import android.os.SystemProperties;
import android.os.ServiceManager;
import android.os.Handler;
import android.os.Message;
import com.android.internal.telephony.ITelephony;
import android.util.Log;

public class CustomSetSn {
    private static final String TAG = "lei";

    private static final int MESSAGE_READ_NV_START= 700;
    private static final int MESSAGE_READ_NV_DETECT= 800;

    private static int mNeedReadNVsCount = 0;
    private static int mNeedReadNVs[] = {6853,6854};
    private final static int TIMEOUT = 1000;
    private static String mSnNumWfi = null;
    private static String mPnNumWfi = null;

    public CustomSetSn(){
	if(Build.LCT_PROJECT_NAME.contains("lxf_p3590_b01")
		|| Build.LCT_PROJECT_NAME.contains("lxf_p3590_b11")
                || Build.LCT_PROJECT_NAME.contains("lxf_p3590_b02")
		|| Build.LCT_PROJECT_NAME.contains("lxf_p3588_b01")
                || Build.LCT_PROJECT_NAME.contains("lxf_p3588_b02")
		|| Build.LCT_PROJECT_NAME.contains("lxf_p3588_b03")){
            readWifiSN();
         } else {
            readSN();
        }
    }

    private void readWifiSN(){
	Log.d(TAG,"readWifiSN");
        handler.sendEmptyMessage(MESSAGE_READ_NV_START);
    }

    private String readSN(){
	Log.d(TAG,"readSN");
        if(Build.CUSTOM_NAME.contains("Lenovo")){
            byte[] result = readNVItems(6854);
	    String mSerial = new String(result);
            result=readNVItems(6853); //PN = new String(result);
	    Log.d(TAG,"CustomSetSn mSerial="+ mSerial);
            SystemProperties.set("ro.lenovosn2", mSerial);
            return mSerial;
        }
        return Build.SERIAL;
    }

    private static byte[] readNVItems(int item) {
        return readNVItems(item, 0);
    }

    private static byte[] readNVItems(int item, int subs) {
        ITelephony tel = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
        byte[] input = new byte[6];
        byte[] output1, output2;
        int i;
        input[0] = 0x00;
        input[1] = 0x00;
        input[2] = (byte)(item & 0xff);
        input[3] = (byte)(item>>8 & 0xff);
        input[4] = (byte)(item>>16 & 0xff);
        input[5] = (byte)(item>>24 & 0xff);
        try {
            output1 = tel.lctOemCommand(input, subs);
            for (i = 0; i < output1.length; i++) {
                if (output1[i] == 0x00)
                    break;
            }
            output2 = new byte[i];
            System.arraycopy(output1, 0, output2, 0, i);
            return output2;
        } catch (Exception ex) {
            Log.e(TAG, "exception on readNVItems: ", ex);
            return null;
        }
    }


    Handler handler = new Handler() {
        public void handleMessage(Message msg) {
                switch (msg.what) {
                    case MESSAGE_READ_NV_START:
                        mNeedReadNVsCount = 0;
                        Config.readNV(mNeedReadNVs[mNeedReadNVsCount]);
                        handler.sendEmptyMessageDelayed(MESSAGE_READ_NV_DETECT, TIMEOUT);
                        break;
                    case MESSAGE_READ_NV_DETECT:
                        if (Config.isProcessing()){
                            handler.sendEmptyMessageDelayed(MESSAGE_READ_NV_DETECT, TIMEOUT);
                        } else {
                            String nvValue = Config.getNvValue();
                            switch(mNeedReadNVs[mNeedReadNVsCount]){
                                case 6854:
                                    if((nvValue != null) && (nvValue.toString().length() != 0)){
                                        mSnNumWfi = nvValue;
                                    }else{
                                        mSnNumWfi = " null";
                                    }
                                    break;
                                case 6853:
                                    if((nvValue != null) && (nvValue.toString().length() != 0)){
                                        mPnNumWfi =  nvValue;
                                    }else{
                                        mPnNumWfi = "";
                                    }
                                    break;
                                default:
                                    break;
                            }
                            int count = mNeedReadNVs.length;
                            if (mNeedReadNVsCount < (count-1)){
                                mNeedReadNVsCount++;
                                Config.readNV(mNeedReadNVs[mNeedReadNVsCount]);
                                handler.sendEmptyMessageDelayed(MESSAGE_READ_NV_DETECT, TIMEOUT);
                            } else {
                                handler.removeMessages(MESSAGE_READ_NV_DETECT);
				Log.d(TAG,"customsn="+"PN:"+ mPnNumWfi + "\nSN:"+mSnNumWfi);
                                if((mPnNumWfi != null && !mPnNumWfi.equals("")) && (mSnNumWfi !=null && !mSnNumWfi.equals(""))){
				    SystemProperties.set("ro.lenovosn2", mSnNumWfi);
                                }
                            }
                        }
                        break;
                }
        }
    };
}

2,新建frameworks/base/services/core/java/com/android/server/customized/WatchCat.java文件,这个文件就是我们实现向dev/log路径下写文件的主要方法.

package com.android.server.customized;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Scanner;
import android.content.Intent;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.util.Log;

public class WatchCat {
	private Context mContext;
	public static String UNLOCK = "001";
	public static String M_TIME = "002";
	public static String REBOOT = "003";
	public static String UPGRADE = "004";
	public static String INSTALL = "005";
	public static String UNINSTALL = "006";
	public static String DEF_DISCRIBE = "NONE";
	public static String DEF_SPLIT = "|";
	public static String RESULT_NO = "0";
	public static String RESULT_YES = "1";

	private static WatchCat sWatchdog;
	private String gaodzInput;
	private String DeviceID;
	private final File mFile = new File("/data/misc/log/mdm");
	private static Handler mHandler;

	public static WatchCat getInstance(Context context) {
		if (sWatchdog == null) {
			sWatchdog = new WatchCat(context);
		}
		return sWatchdog;
	}

	public WatchCat(Context context) {
		mContext = context;
	}

	public void customPerpetual(String input, boolean isTest) {
		if(isTest){
		    gaodzInput = input;
		}else{
		    gaodzInput = getTime() + getDevice() + input;
		}
		Log.d("gaodz", "gaodzInput = " + gaodzInput);
		Appendwrite(gaodzInput,isTest);
                checkFile();
	}

	private void Appendwrite(String mInput, boolean isclean) {
		BufferedWriter out = null;
		try {
			if (isclean) {
				out = new BufferedWriter(new FileWriter(mFile));
			} else {
				out = new BufferedWriter(new OutputStreamWriter(
						new FileOutputStream(mFile, true)));
			}
			out.write(mInput);
			out.newLine();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			Log.d("gaodz", "Appendwrite IOException+" + e);
		}
	}

	public void checkFile() {
		if (readFile() >= 10000) {
                    Intent intent = new Intent();
                    intent.setClassName("com.android.systemui",
                            "com.android.systemui.CustomDialog");
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
		    mContext.startActivity(intent);
		}
	}

	private int readFile() {
		try {
			int count = 1;
			if (!mFile.exists())
				return -1;
			FileInputStream fis = new FileInputStream(mFile);

			Scanner scanner = new Scanner(fis);
			while (scanner.hasNextLine()) {
				scanner.nextLine();
				count++;
			}
			Log.d("gaodz", "count = " + count);
			return count;
		} catch (FileNotFoundException e) {
			Log.d("gaodz", "readFile FileNotFoundException");
			e.printStackTrace();
		}
		return -1;
	}

	private String getTime() {
		SimpleDateFormat sDateFormat = new SimpleDateFormat(
				"yyyy-MM-dd hh:mm:ss");
		String date = sDateFormat.format(new java.util.Date());
		return date + DEF_SPLIT;
	}

	private String getDevice() {
		if (DeviceID == null) {
			TelephonyManager telephonyManager = (TelephonyManager) mContext
					.getSystemService(Context.TELEPHONY_SERVICE);
			telephonyManager.getDeviceId();
			DeviceID = telephonyManager.getDeviceId() + DEF_SPLIT;
		}
		return DeviceID;
	}
}

3, 新建frameworks/base/services/core/java/com/android/server/customized/Config.java,这个文件时定义NV值的文件

package com.android.server.customized;

import android.content.Context;
import android.os.AsyncResult;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.android.internal.util.ReadWriteNV;

public class Config {

    private static ReadWriteNV mReadWriteNV = null;
    private static final int EVENT_READ_NV_COMPLETE = 103;
    private static String nv_value;
    private static boolean mReadNVComplete = false;
    private static Context mContext;

    public Config() {
	mReadWriteNV = ReadWriteNV.getInstance();
    }

    private static final Handler mHandler = new Handler() {
        AsyncResult ar;
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case EVENT_READ_NV_COMPLETE:
                    ar = (AsyncResult)msg.obj;
                    if ((ar.exception == null) && (ar.result != null)) {
                        nv_value = (String) ar.result;
                        mReadNVComplete = true;
                    }
                    break;
            }
        }
    };

    public static boolean isProcessing(){
        return mReadWriteNV.isProcessing();
    }

    public static String getNvValue(){
        return nv_value;
    }

    public static void registerForReadNVRegistrants(){
        mReadWriteNV.registerForReadWriteNVRegistrants(mHandler, EVENT_READ_NV_COMPLETE, null);
    }

    public static void unregisterForReadNVRegistrants(){
        mReadWriteNV.unregisterForReadWriteNVRegistrants(mHandler);
    }

    public static void readNV(int item) {
        try {
            mReadWriteNV.readnv(item);
        }catch (Exception ex) {

        }
    }
}

4.然后需要在init.rc中定义路径的关联,将/data/misc/log和/dev/log关联起来,关联之后两个路径就相当于是同一个路径,读写/dev/log和读写/data/misc/log结果是一样的,那么为什么要关联呢,直接对/dev/log进行读写就可以不是吗?答案是关联是因为/dev/log读写的文件在系统进行重启后会消失,而data/misc/log则不会,关联代码如下:

 
    mkdir /data/misc/log/ 0770 root system  //新建/data/misc/log/路径
    chmod 0777 /data/misc/log/mdm    //赋予可读可写可执行权限


   # add lei
    symlink /data/misc/log /dev/log    //关联两个路径
    chown system system /dev/log/mdm    
    chmod 0777 /dev/log/mdm

 

4, 在system/sepolicy/platform_app.te对log_device进程进行权限赋予

allow platform_app log_device:dir { read write add_name open create search ioctl };
allow platform_app log_device:file { read write create append open };

5,修改system/sepolicy/system_app.te文件,对log_device进程进行权限赋予

allow system_app log_device:dir { read write add_name open create search ioctl };
allow system_app log_device:file { read write create append open };

6,在device/qcom/common/common64.mk中提前j将文件data/misc/log/mdm创建,系统会将这个文件提前编译进去

$(shell mkdir  -p out/target/product/msm8953_64/data/misc/log/)
$(shell touch out/target/product/msm8953_64/data/misc/log/mdm)

7,WatchCat中有定义检查mdm文件,如果写入超过1000条就会提示是否清除记录

首先新建frameworks/base/packages/SystemUI/src/com/android/systemui/CustomDialog.java

+package com.android.systemui;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;
import android.app.customized.CustomizedManager;

public class CustomDialog extends Activity{


	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		showDialog();
	}

	private void showDialog() {
		AlertDialog.Builder builder = new AlertDialog.Builder(CustomDialog.this);
		builder.setTitle(R.string.custom_title).setMessage(R.string.custom_message)
				.setPositiveButton(R.string.custom_yes, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						try {
							CustomizedManager CM = new CustomizedManager(CustomDialog.this);
							CM.setCustomlog(" ",true);
							CustomDialog.this.finish();
						} catch (Exception e) {
							Log.d("gaodz", "mFile.delete Exception");
						}
					}
				})
				.setNegativeButton(R.string.custom_no, new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface dialog, int id) {
						CustomDialog.this.finish();
					}
				});
		builder.create();
		builder.show();
	}
}

8,在frameworks/base/packages/SystemUI/AndroidManifest.xml中定义下这个activity

        <activity
            android:name="com.android.systemui.CustomDialog"
            android:launchMode="singleInstance"
            android:theme="@style/Transparent" >
        </activity>

9,将CustomDialog显示时所依赖的theme和引用的字符定义一下,

frameworks/base/packages/SystemUI/res/values/strings.xml

   <string name="mia_title">警告</string>
   <string name="mia_message">信息记录已经超过10000条,是否清除记录?</string>
   <string name="mia_yes">确定</string>
   <string name="mia_no">取消</string>

还有frameworks/base/packages/SystemUI/res/values/styles.xml

    <style name="Transparent" parent="android:style/Theme.Dialog">
        <item name="android:windowNoTitle">true</item>
        <item name="android:windowIsTranslucent">false</item>
        <item name="android:windowIsFloating">true</item>
        <item name="android:backgroundDimEnabled">false</item>
    </style>

现在自己写的三方应用,就可以直接对/dev/log进行读写了,而且重启后文件不会消失~

猜你喜欢

转载自blog.csdn.net/lancelots/article/details/82746343