SEAndroidManager Patches for AVC denied message logging.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I have some patches to SEAndroidManager that we found useful for our device when on the go. It lets you view the AVC Denied messages from the device from within the Android Manager App. No more using terminal emulator and dmesg | grep...typing on a touch screen is no fun.

patches/0001-AVC-Denied-message-parsing-framework-in-place.patch
patches/0002-Working-logger.patch


--
Respectfully,

William C Roberts


From 56861e056337197bdb55cd413c1d410b69ff1e1c Mon Sep 17 00:00:00 2001
From: William Roberts <w.roberts@xxxxxxxxxxxxxxx>
Date: Fri, 23 Mar 2012 18:20:38 -0700
Subject: [PATCH 1/2] AVC Denied message parsing framework in place.

---
 jni/Android.mk                                     |   13 +
 jni/klogctl.c                                      |   28 ++
 jni/klogctl.h                                      |   22 ++
 project.properties                                 |    2 +-
 src/com/android/seandroid_manager/AVCCallback.java |    7 +
 .../seandroid_manager/AVCDeniedMessage.java        |  303 ++++++++++++++++++++
 src/com/android/seandroid_manager/AVCReader.java   |   87 ++++++
 src/com/android/seandroid_manager/KLogCtl.java     |   40 +++
 .../seandroid_manager/SEAndroidManager.java        |   24 ++-
 9 files changed, 523 insertions(+), 3 deletions(-)
 create mode 100644 jni/Android.mk
 create mode 100644 jni/klogctl.c
 create mode 100644 jni/klogctl.h
 create mode 100644 src/com/android/seandroid_manager/AVCCallback.java
 create mode 100644 src/com/android/seandroid_manager/AVCDeniedMessage.java
 create mode 100644 src/com/android/seandroid_manager/AVCReader.java
 create mode 100644 src/com/android/seandroid_manager/KLogCtl.java

diff --git a/jni/Android.mk b/jni/Android.mk
new file mode 100644
index 0000000..45948d2
--- /dev/null
+++ b/jni/Android.mk
@@ -0,0 +1,13 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE    := libjni_klogctl
+LOCAL_SRC_FILES := klogctl.c
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SHARED_LIBRARIES := liblog
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/jni/klogctl.c b/jni/klogctl.c
new file mode 100644
index 0000000..1f36e5c
--- /dev/null
+++ b/jni/klogctl.c
@@ -0,0 +1,28 @@
+#include <string.h>
+#include <jni.h>
+#include <errno.h>
+
+#define LOG_TAG "klogctl"
+
+ #include <cutils/log.h>
+#include "klogctl.h"
+
+extern int klogctl(int type, char *buf, int length);
+
+JNIEXPORT
+jint
+JNICALL
+Java_com_android_seandroid_1manager_KLogCtl_kLogCtl(JNIEnv *env, jclass thiz, jint type, jbyteArray buf, jint length) {
+
+	jint error;
+	jboolean is_copy;
+	jbyte *bytes = (buf) ? (*env)->GetByteArrayElements(env, buf, &is_copy) : NULL;
+
+	error = klogctl(type, (char *)bytes, length);
+
+	if(bytes) {
+		(*env)->ReleaseByteArrayElements(env, buf, bytes, 0);
+	}
+	return (error != -1) ? error : errno;
+}
+
diff --git a/jni/klogctl.h b/jni/klogctl.h
new file mode 100644
index 0000000..5496263
--- /dev/null
+++ b/jni/klogctl.h
@@ -0,0 +1,22 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_seandroid_manager_KLogCtl */
+
+#ifndef _Included_com_android_seandroid_manager_KLogCtl
+#define _Included_com_android_seandroid_manager_KLogCtl
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Class:     com_android_seandroid_manager_KLogCtl
+ * Method:    kLogCtl
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_android_seandroid_1manager_KLogCtl_kLogCtl
+  (JNIEnv *, jclass, jint, jbyteArray, jint);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/project.properties b/project.properties
index b904742..8da376a 100644
--- a/project.properties
+++ b/project.properties
@@ -8,4 +8,4 @@
 # project structure.
 
 # Project target.
-target=android-13
+target=android-15
diff --git a/src/com/android/seandroid_manager/AVCCallback.java b/src/com/android/seandroid_manager/AVCCallback.java
new file mode 100644
index 0000000..34d8632
--- /dev/null
+++ b/src/com/android/seandroid_manager/AVCCallback.java
@@ -0,0 +1,7 @@
+package com.android.seandroid_manager;
+
+public interface AVCCallback {
+
+	public void handleAVCEvent(AVCDeniedMessage message);
+	
+}
diff --git a/src/com/android/seandroid_manager/AVCDeniedMessage.java b/src/com/android/seandroid_manager/AVCDeniedMessage.java
new file mode 100644
index 0000000..e5070da
--- /dev/null
+++ b/src/com/android/seandroid_manager/AVCDeniedMessage.java
@@ -0,0 +1,303 @@
+package com.android.seandroid_manager;
+
+import android.util.Log;
+
+/**
+ * 
+ * The class parses a raw kmsg into a formated AVC denied message.
+ *
+ */
+public class AVCDeniedMessage {
+	
+	private String logTag="AVCDeniedMessage";
+	
+	private String message = null;
+	private String time = null;
+	private String name = null;
+	private String pid = null;
+	private String path = null;
+	private String command = null;
+	private String capability = null;
+	private String scontext = null;
+	private String tcontext = null;
+	private String tclass = null;
+	private String dev = null;
+	private String inode = null;
+	
+	AVCDeniedMessage() { }
+	
+	/** Constructs a new AVCDenied object from an avc denied log line in kmsg.
+	 * 
+	 * @param message
+	 *   The message obtained from dmesg, ie the line that contains the avc denied message.
+	 */
+	AVCDeniedMessage(String message) {
+		this.message = message;
+		parse();
+	}
+	
+	/** Set a new message into an AVCDenied message.
+	 * 
+	 * @param message
+	 *   The message obtained from dmesg, ie the line that contains the avc denied message.
+	 */
+	public void setMessage(String message) {
+		this.message=message;
+		parse();
+	}
+	
+	/** Gets the device field from the AVC denied message.
+	 * 
+	 * @return
+	 *   The device field or null if not set or null if object is not valid.
+	 */
+	public String getDev() {
+		
+		return dev;
+	}
+	
+	/** Gets the ino field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   return inode number or null if not set or null if object is not valid.
+	 */
+	public String getInode() {
+		
+		return inode;
+	}
+	
+	/** Gets the name of the process out of the AVC denied message.
+	 * 
+	 * @return
+	 *   The process name, or null if object is not valid.
+	 */
+	public String getName() {
+		
+		return name;
+	}
+
+	/** Gets the time field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   The time field in kernel log format (Ticks since boot), or null if object is not valid. 
+	 */
+	public String getTime() {
+		
+		return time;
+	}
+
+	/** Gets the PID field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   PID or null if object is not valid.
+	 */ 
+	public String getPid() {
+		
+		return pid;
+	}
+
+	/** Gets the path field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   Path or null if not set or null if object is not valid.
+	 */
+	public String getPath() {
+		
+		return path;
+	}
+	
+	/** Gets the comm field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   comm or null if not set or null if object is not valid.
+	 */
+	public String getCommand() {
+		
+		return command;
+	}
+	
+	/** Gets the scontext field out of the AVC denied message.
+	 * 
+	 * @return
+	 *  scontext null if object is not valid.
+	 */
+	public String getSContext() {
+		
+		return scontext;
+	}
+	
+	/** Gets the tcontext field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   tcontext or null if object is not valid.
+	 */
+	public String getTContext() {
+		
+		return tcontext;
+	}
+
+	/** Gets the tclass field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   tclass or null if object is not valid.
+	 */
+	public String getTClass() {
+		
+		return tclass;
+	}
+
+	/** Gets the cap field out of the AVC denied message.
+	 * 
+	 * @return
+	 *   cap or null if not set or null if object is not valid.
+	 */
+	public String getCapability() {
+		
+		return capability;
+	}
+
+	/** Gets the raw message set in the constructor.
+	 * 
+	 * @return
+	 *   raw message.
+	 */
+	public String getRawMessage() {
+		
+		return message;
+	}
+	
+	/** Tests whether or not the object is valid or not.
+	 * 
+	 * Tests to see if the message passed during the constructor is a properly
+	 * formated avc denied message.
+	 * 
+	 * @return
+	 *   True if it is valid, False if it is not valid.
+	 */
+	public boolean isValid() {
+		return (message != null);
+	}
+	
+	/** Returns a formated AVC denied message.
+	 * 
+	 * @return
+	 *   A formated AVC denied message.
+	 */
+	public String toString() {
+		
+		String output = null;
+		
+		if(this.isValid()) {
+			output += "Time: " + time;
+			output += " Process: " + name;
+			output += " PID: " + pid;
+			output += " Command: " + command;
+			
+			if(message.length() == 20) {
+				output += " Path: " + path;
+				output += " Dev: " + dev;
+				output += " Inode: " + inode;
+			}
+			else if(message.length() == 19) {
+				output += " Capability: " + capability;
+			}
+			else if(message.length() == 18){
+				output += " Name: " + name;
+			}
+			
+			output += " SContext: " + scontext;
+			output += " TContext: " + tcontext;
+			output += " TClass: " + tclass;				
+		}
+		
+		return output;
+	}
+	
+	/** Parse this.message and store the formatted data.
+	 * 
+	 */
+	private void parse() {
+		
+		/*
+		 * After splitting the AVC denied message around " " (space), the message has the following
+		 * format in the array.
+		 * 
+		 * For AVC messages with a length of 20, the format is as follows:
+		 * 0 --> time
+		 * 8 --> process_name
+		 * 12 pid=xxx
+		 * 13 comm=xxx
+		 * ----------------------common
+		 * 14 path=xxx
+		 * 15 dev=xxx
+		 * 16 ino=xxx
+		 * 17 scontext=xxx
+		 * 18 tcontext=xxx
+		 * 19 tclass=xxx
+		 *
+		 * For AVC messages with a length of 19, the format is as follows:
+		 * 0 --> time
+		 * 8 --> process_name
+		 * 12 pid=xxx
+		 * 13 comm=xxx
+		 * ----------------------common
+		 * 14 name=xxx
+		 * 15 scontext=xxx
+		 * 16 tcontext=xxx
+		 * 17 tclass=xxx
+		 * 
+		 * For AVC messages with a length of 18, the format is as follows:
+		 * 0 --> time
+		 * 8 --> process_name
+		 * 12 pid=xxx
+		 * 13 comm=xxx
+		 * ----------------------common
+		 * 14 name=xxx
+		 * 15 scontext=xxx
+		 * 16 tcontext=xxx
+		 * 17 tclass=xxx
+		 */
+		String subparts[] = message.split(" ");
+		
+		/*Common*/
+		time = subparts[0].substring(subparts[0].indexOf('[')+1, subparts[0].indexOf(']')); /*<5>[85474.589385]*/
+		name = subparts[8];
+		pid = subparts[12].split("=")[1];
+		command = subparts[13].split("=")[1];
+		
+		/*Length 20*/
+		if(subparts.length == 20) {
+			path = subparts[14].split("=")[1];
+			dev = subparts[15].split("=")[1];
+			inode = subparts[16].split("=")[1];
+			scontext = subparts[17].split("=")[1];
+			tcontext = subparts[18].split("=")[1];
+			tclass = subparts[19].split("=")[1];
+		}
+		/*Length 19*/
+		else if(subparts.length == 19) {
+			capability = subparts[14].split("=")[1];
+			scontext = subparts[16].split("=")[1];
+			tcontext = subparts[17].split("=")[1];
+			tclass = subparts[18].split("=")[1];
+		}
+		/*Length 18*/
+		else if(subparts.length == 18) {
+			name = subparts[14].split("=")[1];
+			scontext = subparts[15].split("=")[1];
+			tcontext = subparts[16].split("=")[1];
+			tclass = subparts[17].split("=")[1];
+		}
+		/*Length 17*/
+		else if(subparts.length == 17) {
+			scontext = subparts[14].split("=")[1];
+			tcontext = subparts[15].split("=")[1];
+			tclass = subparts[16].split("=")[1];
+		}
+		else {
+			Log.e(logTag, "Could not parse \""+message+"\", length: "+subparts.length+" unknown!");
+			message = time = name = pid = command = null;
+		}
+	}
+	
+}
diff --git a/src/com/android/seandroid_manager/AVCReader.java b/src/com/android/seandroid_manager/AVCReader.java
new file mode 100644
index 0000000..866f595
--- /dev/null
+++ b/src/com/android/seandroid_manager/AVCReader.java
@@ -0,0 +1,87 @@
+package com.android.seandroid_manager;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.util.Scanner;
+
+import android.util.Log;
+
+/**
+ * 
+ * Reads the kernel message log and sends AVCDenied messages to
+ * the registered handler.
+ *
+ */
+public class AVCReader {
+
+	private String avcSearchTag = "avc";
+	private String logTag = "AVCReader";
+	private AVCCallback callback = null;
+	private static final AVCReader instance = new AVCReader();
+	
+	private AVCReader() {}
+	
+	/** Get the Singleton instance.
+	 * 
+	 * @return
+	 *  the AVCReader singleton instance.
+	 */
+	public static synchronized AVCReader getInstance() {
+		return instance;
+	}
+	
+	/** Register a handler to handle avc denied messages.
+	 * 
+	 * @param avcHandler
+	 *   The call back to handle AVC denied events.
+	 *   
+	 * @param overide
+	 *   Whether or not to override an existing event handler, if true, then
+	 *   all calls will succeed and the existing handler will be replaced
+	 *   by avcHandler. On false, the call will succeed only if your registering the
+	 *   first handler.
+	 *  
+	 * @return
+	 *   True if successful, False otherwise. 
+	 */
+	public synchronized boolean registerCallback(AVCCallback avcHandler, boolean overide) {
+		
+		if((avcHandler != null) && (overide || (callback == null))) {
+				callback = avcHandler;
+				return true;
+		}
+		Log.e(logTag, "Could not set handler");  
+		return false;
+	} 
+	
+	/** Reads from kernel logs, parses them and generates callbacks set by registerCallback
+	 * for each avc denied message encountered.
+	 * 
+	 */
+	public void parseLogs() {
+		
+		int value;
+		byte logs[];
+		String line;
+		AVCDeniedMessage message;
+		
+		value = KLogCtl.kLogCtl(10, null, 0);
+		
+		logs = new byte[value];
+		value = KLogCtl.kLogCtl(3, logs, value);
+
+		Scanner stream = new Scanner(new ByteArrayInputStream(logs));
+		
+		while(stream.hasNextLine()) {
+			line = stream.nextLine();
+			if(line.contains(avcSearchTag)) {
+				
+				message = new AVCDeniedMessage(line);
+				callback.handleAVCEvent(message);
+			}
+		}
+		return;
+	}
+}
diff --git a/src/com/android/seandroid_manager/KLogCtl.java b/src/com/android/seandroid_manager/KLogCtl.java
new file mode 100644
index 0000000..03cb5f6
--- /dev/null
+++ b/src/com/android/seandroid_manager/KLogCtl.java
@@ -0,0 +1,40 @@
+package com.android.seandroid_manager;
+
+public class KLogCtl {
+	
+	/** Reads from the kernel logs. 
+	 * 
+	 * See man klogctl
+	 * 
+	 * @param type
+	 *   Determines the action to be taken by this function.
+	 *          Quoting from kernel/printk.c:
+	 *  Commands to sys_syslog:
+	 *
+	 *      0 -- Close the log.  Currently a NOP.
+	 *      1 -- Open the log. Currently a NOP.
+	 *      2 -- Read from the log.
+	 *      3 -- Read all messages remaining in the ring buffer.
+	 *      4 -- Read and clear all messages remaining in the ring buffer
+	 *      5 -- Clear ring buffer.
+	 *      6 -- Disable printk to console
+	 *      7 -- Enable printk to console
+	 *      8 -- Set level of messages printed to console
+	 *      9 -- Return number of unread characters in the log buffer
+	 *     10 -- Return size of the log buffer
+	 *   
+	 * @param buf
+	 *  Buffer to read the kernel log into.
+	 *  
+	 * @param length
+	 *  The number of bytes to read.
+	 *  
+	 * @return
+	 *  0 on success or one of the stderror codes on error.
+	 */
+	public static native int kLogCtl(int type, byte buf[], int length);
+	
+	static {
+		System.loadLibrary("jni_klogctl");
+	}
+}
diff --git a/src/com/android/seandroid_manager/SEAndroidManager.java b/src/com/android/seandroid_manager/SEAndroidManager.java
index cf43f56..d0b0c52 100644
--- a/src/com/android/seandroid_manager/SEAndroidManager.java
+++ b/src/com/android/seandroid_manager/SEAndroidManager.java
@@ -11,6 +11,7 @@ import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
 import android.provider.Settings;
+import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -19,9 +20,11 @@ import android.widget.ArrayAdapter;
 import android.widget.CheckBox;
 import android.widget.TextView;
 
+import java.io.FileNotFoundException;
 import java.util.List;
 
-public class SEAndroidManager extends PreferenceActivity {
+public class SEAndroidManager extends PreferenceActivity implements AVCCallback {
+
     @Override
     public void onBuildHeaders(List<Header> target) {
         loadHeadersFromResource(R.xml.seandroid_manager_headers, target);
@@ -30,7 +33,6 @@ public class SEAndroidManager extends PreferenceActivity {
     public static class SELinuxEnforcingFragment extends PreferenceFragment {
 
         private static final String KEY_SELINUX_ENFORCING = "selinux_enforcing";
-
         private CheckBoxPreference mSELinuxToggleEnforce;
 
         @Override
@@ -121,4 +123,22 @@ public class SEAndroidManager extends PreferenceActivity {
             setListAdapter(mAdapter);
         }
     }
+
+	@Override
+	public void handleAVCEvent(AVCDeniedMessage message) {
+		/*TODO: Handle message here and post to screen*/
+		Log.d("Message: ", message.toString());
+		
+	}
+	
+	@Override
+	public void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+		/* TODO: Example code for reading the avc denied messages, need to remove when
+		 * implementation is complete.
+		AVCReader reader = AVCReader.getInstance();
+		reader.registerCallback(this, false);
+		reader.parseLogs();
+		*/
+	}
 }
-- 
1.7.0.4

From 23e31e410f3815fde40ab72725c0d6bbda381c53 Mon Sep 17 00:00:00 2001
From: William Roberts <w.roberts@xxxxxxxxxxxxxxx>
Date: Mon, 26 Mar 2012 17:56:24 -0700
Subject: [PATCH 2/2] Working logger

---
 res/layout/avc_denied_reader.xml                   |   40 +++++++++
 res/values/strings.xml                             |    5 +
 res/xml/seandroid_manager_headers.xml              |    5 +
 src/com/android/seandroid_manager/AVCCallback.java |   19 ++++
 src/com/android/seandroid_manager/AVCReader.java   |   75 +++++++----------
 .../seandroid_manager/SEAndroidManager.java        |   91 +++++++++++++++-----
 6 files changed, 168 insertions(+), 67 deletions(-)
 create mode 100644 res/layout/avc_denied_reader.xml

diff --git a/res/layout/avc_denied_reader.xml b/res/layout/avc_denied_reader.xml
new file mode 100644
index 0000000..5cecec7
--- /dev/null
+++ b/res/layout/avc_denied_reader.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+        android:id="@+id/linearLayout1"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent"
+        android:orientation="vertical" >
+
+        <RelativeLayout
+            android:id="@+id/linearLayout2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" >
+
+            <Button
+                android:id="@+id/refreshButton"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_centerHorizontal="true"
+                android:layout_centerVertical="true"
+                android:layout_alignParentRight="@+id/linearLayout2"
+                android:text="@string/avc_denied_log_refresh_button_label"
+                android:layout_toRightOf="@+id/textView1" />
+
+        </RelativeLayout>
+
+        
+        <ScrollView
+            android:id="@+id/avcLogScrollView"
+            android:layout_width="fill_parent"
+            android:layout_height="fill_parent">    
+          
+            <TextView
+                android:id="@+id/avcLogTextView"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:text="@string/avc_denied_log_reload_msg" />
+            
+        </ScrollView>
+            
+        
+    </LinearLayout>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f892438..7c4834a 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -14,4 +14,9 @@
     <string name="selinux_manage_booleans">SELinux Booleans</string>
     <string name="selinux_manage_booleans_summary">Manage SELinux Booleans</string>
     <string name="selinux_no_booleans">No Booleans</string>
+    <string name="avc_denied_log_fragment_title">AVC Denied Logs</string>
+    <string name="avc_denied_log_reload_msg">Press The "Refresh" Button to Update AVC Denied Messages</string>
+    <string name="avc_denied_log_refresh_button_label">Refresh</string>
+    <string name="avc_denied_log_refresh_text">Refresh AVC Logs</string>
 </resources>
+
diff --git a/res/xml/seandroid_manager_headers.xml b/res/xml/seandroid_manager_headers.xml
index bd63280..12db791 100644
--- a/res/xml/seandroid_manager_headers.xml
+++ b/res/xml/seandroid_manager_headers.xml
@@ -12,4 +12,9 @@
         android:title="@string/selinux_boolean_fragment_title">
     </header>
 
+    <header
+        android:fragment="com.android.seandroid_manager.SEAndroidManager$AVCDeniedReaderFragment"
+        android:title="@string/avc_denied_log_fragment_title">
+    </header>
+
 </preference-headers>
diff --git a/src/com/android/seandroid_manager/AVCCallback.java b/src/com/android/seandroid_manager/AVCCallback.java
index 34d8632..8da986e 100644
--- a/src/com/android/seandroid_manager/AVCCallback.java
+++ b/src/com/android/seandroid_manager/AVCCallback.java
@@ -1,7 +1,26 @@
 package com.android.seandroid_manager;
 
+/** 
+ * Used to handle events from parsing the kernel logs looking for AVC messages.
+ * 
+ */
 public interface AVCCallback {
 
+	/** Before parsing begins, this function is called.
+	 * 
+	 */
+	public void onStart();
+	
+	/** For each AVC denied message encountered, this callback is called.
+	 * 
+	 * @param message
+	 *  The exact AVC denied message encountered while parsing.
+	 */
 	public void handleAVCEvent(AVCDeniedMessage message);
 	
+	/** This is called at the end of parsing, when no more messages are found.
+	 * 
+	 */
+	public void onFinish();
+	
 }
diff --git a/src/com/android/seandroid_manager/AVCReader.java b/src/com/android/seandroid_manager/AVCReader.java
index 866f595..33ba378 100644
--- a/src/com/android/seandroid_manager/AVCReader.java
+++ b/src/com/android/seandroid_manager/AVCReader.java
@@ -1,12 +1,9 @@
 package com.android.seandroid_manager;
 
 import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.util.Scanner;
 
-import android.util.Log;
+import android.os.AsyncTask;
 
 /**
  * 
@@ -14,53 +11,20 @@ import android.util.Log;
  * the registered handler.
  *
  */
-public class AVCReader {
+public class AVCReader extends AsyncTask<Void, AVCDeniedMessage, Void> {
 
 	private String avcSearchTag = "avc";
-	private String logTag = "AVCReader";
 	private AVCCallback callback = null;
-	private static final AVCReader instance = new AVCReader();
 	
-	private AVCReader() {}
-	
-	/** Get the Singleton instance.
-	 * 
-	 * @return
-	 *  the AVCReader singleton instance.
-	 */
-	public static synchronized AVCReader getInstance() {
-		return instance;
+	public AVCReader(AVCCallback avcHandler) {	
+			callback = avcHandler;
 	}
 	
-	/** Register a handler to handle avc denied messages.
-	 * 
-	 * @param avcHandler
-	 *   The call back to handle AVC denied events.
-	 *   
-	 * @param overide
-	 *   Whether or not to override an existing event handler, if true, then
-	 *   all calls will succeed and the existing handler will be replaced
-	 *   by avcHandler. On false, the call will succeed only if your registering the
-	 *   first handler.
-	 *  
-	 * @return
-	 *   True if successful, False otherwise. 
-	 */
-	public synchronized boolean registerCallback(AVCCallback avcHandler, boolean overide) {
-		
-		if((avcHandler != null) && (overide || (callback == null))) {
-				callback = avcHandler;
-				return true;
-		}
-		Log.e(logTag, "Could not set handler");  
-		return false;
-	} 
-	
-	/** Reads from kernel logs, parses them and generates callbacks set by registerCallback
+	/** Reads from kernel logs, parses them and calls the callbacks set by registerCallback
 	 * for each avc denied message encountered.
 	 * 
 	 */
-	public void parseLogs() {
+	private void parseLogs() {
 		
 		int value;
 		byte logs[];
@@ -74,14 +38,37 @@ public class AVCReader {
 
 		Scanner stream = new Scanner(new ByteArrayInputStream(logs));
 		
-		while(stream.hasNextLine()) {
+		while(stream.hasNextLine() && !isCancelled()) {
 			line = stream.nextLine();
 			if(line.contains(avcSearchTag)) {
 				
 				message = new AVCDeniedMessage(line);
-				callback.handleAVCEvent(message);
+				publishProgress(message);
 			}
 		}
+		
+		return;
+	}
+
+	@Override
+	protected void onPostExecute(Void result) {
+		callback.onFinish();
+	}
+	
+	@Override
+	protected void onPreExecute() {
+		callback.onStart();
+	}
+	
+	@Override
+	protected Void doInBackground(Void... params) {
+		parseLogs();
+		return null;
+	}
+	
+	@Override
+	protected void onProgressUpdate(AVCDeniedMessage... message) {
+		callback.handleAVCEvent(message[0]);
 		return;
 	}
 }
diff --git a/src/com/android/seandroid_manager/SEAndroidManager.java b/src/com/android/seandroid_manager/SEAndroidManager.java
index d0b0c52..4342bf6 100644
--- a/src/com/android/seandroid_manager/SEAndroidManager.java
+++ b/src/com/android/seandroid_manager/SEAndroidManager.java
@@ -1,6 +1,9 @@
 package com.android.seandroid_manager;
 
+import android.app.Activity;
+import android.app.Fragment;
 import android.app.ListFragment;
+import android.app.ProgressDialog;
 import android.content.Context;
 import android.content.SharedPreferences;
 import android.os.Bundle;
@@ -10,26 +13,86 @@ import android.preference.Preference;
 import android.preference.PreferenceActivity;
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceScreen;
-import android.provider.Settings;
-import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.Button;
 import android.widget.CompoundButton;
 import android.widget.ArrayAdapter;
 import android.widget.CheckBox;
+import android.widget.ScrollView;
 import android.widget.TextView;
+import android.view.View.OnClickListener;
 
-import java.io.FileNotFoundException;
 import java.util.List;
 
-public class SEAndroidManager extends PreferenceActivity implements AVCCallback {
+public class SEAndroidManager extends PreferenceActivity {
 
     @Override
     public void onBuildHeaders(List<Header> target) {
         loadHeadersFromResource(R.xml.seandroid_manager_headers, target);
     }
 
+    public static class AVCDeniedReaderFragment extends Fragment {
+    	
+    	private TextView logs;
+    	private ScrollView scrollView;
+    	private ProgressDialog progressDialog;
+    	
+    	private AVCCallback handleMessage = new AVCCallback() {
+    		
+    		public void onStart() {
+    			progressDialog.show();
+    		}
+    		
+    		public void handleAVCEvent(AVCDeniedMessage message) {
+    			logs.append(message.getRawMessage()+"\n\n");
+    		}
+    		
+    		public void onFinish() {
+    			scrollView.post(new Runnable() { 
+    			    public void run() { 
+    			    	scrollView.fullScroll(ScrollView.FOCUS_DOWN); 
+    			    } 
+    			}); 
+    			progressDialog.cancel();
+    		}
+    		
+    	};
+    	
+    	private OnClickListener onAVCRefreshClick = new OnClickListener() {
+
+			@Override
+			public void onClick(View v) {
+				logs.setText(null);
+				AVCReader logReader = new AVCReader(handleMessage);
+				logReader.execute();
+			}
+    		
+    	};
+    	   	
+        @Override
+        public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            
+            View v = inflater.inflate(R.layout.avc_denied_reader, container, false);
+            
+            Button b = (Button)v.findViewById(R.id.refreshButton); 
+            b.setOnClickListener(onAVCRefreshClick);
+            
+            logs = (TextView)v.findViewById(R.id.avcLogTextView);
+            
+            scrollView = (ScrollView)v.findViewById(R.id.avcLogScrollView);
+            
+            progressDialog = new ProgressDialog(getActivity());
+            progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
+            progressDialog.setMessage("Loading...");
+            
+            return v;                    
+        }
+        
+    }
+    
     public static class SELinuxEnforcingFragment extends PreferenceFragment {
 
         private static final String KEY_SELINUX_ENFORCING = "selinux_enforcing";
@@ -38,8 +101,8 @@ public class SEAndroidManager extends PreferenceActivity implements AVCCallback
         @Override
         public void onCreate(Bundle savedInstanceState) {
             super.onCreate(savedInstanceState);
-
             addPreferencesFromResource(R.xml.selinux_enforcing_fragment);
+
             mSELinuxToggleEnforce = (CheckBoxPreference) getPreferenceScreen().findPreference(KEY_SELINUX_ENFORCING);
             mSELinuxToggleEnforce.setChecked(SELinux.isSELinuxEnforced());
         }
@@ -123,22 +186,4 @@ public class SEAndroidManager extends PreferenceActivity implements AVCCallback
             setListAdapter(mAdapter);
         }
     }
-
-	@Override
-	public void handleAVCEvent(AVCDeniedMessage message) {
-		/*TODO: Handle message here and post to screen*/
-		Log.d("Message: ", message.toString());
-		
-	}
-	
-	@Override
-	public void onCreate(Bundle savedInstanceState) {
-		super.onCreate(savedInstanceState);
-		/* TODO: Example code for reading the avc denied messages, need to remove when
-		 * implementation is complete.
-		AVCReader reader = AVCReader.getInstance();
-		reader.registerCallback(this, false);
-		reader.parseLogs();
-		*/
-	}
 }
-- 
1.7.0.4


[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux