Question

I need to access some proc files in a module on Android kernel. Basically i need the info shown in cat command, like cat /proc/uptime. However i need to do it programmatically.

I tried work with proc_fs functions, but it was just a little fuzzy for me, usually the examples are to create a proc file then read it and that is it. I need to actually use the data from proc files.

I also tred the good fopen, but it does not seems to work on modules.

How can i do that? i'm really newbie on this. I'm working on goldfish Android kernel.

Thanks.

Was it helpful?

Solution

Procfs is an in-memory file system. It is an interface for the userspace to fetch info and put (config) info into the kernel data structures. In other words, procfs enables userspace to interact and look into the kernel data structures the way they exist during runtime.

Hence, any file inside /proc is not meant to be read from inside a kernel or a kernel module. And why would one want to do that? In a monolithic kernel like Linux, you can access the data structures of one subsystem in the kernel through another directly or through a pre-defined function.

The following function call might help:

struct timespec uptime;

do_posix_clock_monotonic_gettime(&uptime);

You can refer to the /proc/uptime implementation at the link below, it is essentially a seq_file.

http://lxr.free-electrons.com/source/fs/proc/uptime.c

OTHER TIPS

I'm responding to the original question, how can a kernel module access files in the procfs.

How a Kernel Module Accesses Files in Special Filesystems

I found the following to be a useful reference: https://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790

I think it's setting sysctl values from the kernel command line. The sequence appears to be as follows:

A. Mount the procfs filesystem

  1. proc_fs_type = get_fs_type("proc");
  2. *proc_mnt = kern_mount(proc_fs_type);

B. Open the file at a path relative to the root of the procfs

  1. file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);

C. Read/Write the file

  1. int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
  2. wret = kernel_write(file, val, len, &pos);

D. Close the file

  1. err = filp_close(file, NULL);

D. Cleanup the filesystem mount

  1. kern_unmount(proc_mnt);
  2. put_filesystem(proc_fs_type);

Should a Kernel Module Access Files in Special Filesystems

Yes, procfs mostly provides user space with read/write access to kernel-level data. Since a kernel module runs in the kernel, if a more direct sequence of API calls exist that allow the module to access such data, use of such API would be preferred as it is likely much cleaner, less code, and more efficient.

However, a dynamically-loaded kernel module doesn't have (clean) direct access to all symbols (or data structures) in the kernel.

A kernel module can only access functions and variables that are

  • defined entirely in a header file that can be included in the kernel-module source

  • or explicitly exposed to kernel modules through one of the macros in /include/asm-generic/export.h:

    • EXPORT_SYMBOL
    • EXPORT_SYMBOL_GPL
    • EXPORT_DATA_SYMBOL
    • EXPORT_DATA_SYMBOL_GPL

Cases where a kernel module needs to access data that is not exposed through such EXPORTED API but accessible through files in procfs or any other special filesystem seem like legitimate cases for accessing such files from kernel modules.

As a general design principle, it is my understanding, that the kernel aims to implement mechanisms without forcing a particular policy. Any feature implemented in a way that forces a policy where user-space has access to data, but a kernel module does not is poorly designed.

Kernel module code, by design, run at the same privilege level as the rest of the kernel. There is no fool-proof way to deny a kernel module access to any data that any other part of the kernel can access. Any such attempts can be circumvented with beautifully ugly hacks.

As an extreme example, on x86 machines, the kernel module can use in-line assembly to directly access control registers, walk page tables, and have it's way with any region of memory it so desires. The same goes for interrupt and exception handlers.

I used top to accomplish this, because it actually gives CPU %. The code I used is as follows

Process process = Runtime.getRuntime().exec("top -n 1");
                //Get the output of top so that it can be read
                BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
                String line;
                //Read every line of the output of top that contains data
                while (((line = bufferedReader.readLine()) != null)) {
                    //Break the line into parts.  Any number of spaces greater than 0 defines a new element
                    numbersC = line.split("[ ]+");              
                    if (i > 6) {  
                        //Some lines start with a space, so their indices are different than others
                        if (numbersC[0].equals("")){
                            //If name contains the string com.android, then it is a process that we want to take values for
                            if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android".toLowerCase())){
                                //Add the name of the process to the Name arraylist, excluding the com.android. part
                                Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                //Add the CPU value of the process to the CPU arraylist, without the % at the end
                                CPU.add(Long.parseLong(numbersC[3].replace("%", "")));  
                            }
                        }
                        else {
                            //This is basically the same as above, except with different index values, as there is no leading space in the numbers array
                            if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android.".toLowerCase())){ 
                                Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                CPU.add(Long.parseLong(numbersC[2].replace("%", "")));
                            }
                        }
                    }
                    i++;
                }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top