Common Linux Commands

  1. ll: Displays file details. On a MAC, you can run the ll command to set an alias:alias ll="ls -alF", can also be usedls -lThe result is the same
  2. More: Similar to CAT, but press space to turn pages one screen at a time
  3. Tail: View data from back to front. Tail-200 Reads the last 200 rows, and tail -f reads the data in real time
  4. Head: Read from front to back
  5. Grep -a /B/C: -a the last 10 lines of the search result. -b First 10 lines; -c 10 lines before and after
  6. Df -h: displays the disk usage
  7. Du-sh: displays the size of a document or folder
  8. Su with sudo: Switches to the super user. The latter executes the command as the super user and retains the current user.
    • Superusers are preceded by #, while regular users are preceded by $

File permissions

  1. r: Read permission;w: Write permission.x: Execute permission;-: Has no corresponding permission
  2. throughls -lView file permissions
    • Such asdrwxr-xr-x: The first d indicates the file type (d indicates the folder, and – indicates the file), followed by the following 9 letters are permissions:Permissions of the current user, group user, and other users

vim

  1. / ABC: searches for ABC. Press n to go to the next search result. Used in non-editing mode
  2. Yy: Copy the current line

drive

A program that operates hardware

  1. The driver is generally divided into character driver, block driver. The main difference between the two is in what form the data is exchanged with the driver, the former as a stream of characters, the latter as a block of data
  2. The application layer accesses the hardware by calling file IO such as open/read/write/ioctl. These operations are system calls that eventually invoke the corresponding methods in the driver in the kernel
  3. Drivers are functions defined in the structure file_operations
  4. Device files refer to files defined in the /dev directoryThe application layer operates device files through file IO, and device files passDevice numberAssociated with the corresponding device driver
    • The device ID consists of the primary device ID and secondary device ID. The primary device number is used to distinguish between species, and the secondary device number is used to distinguish between individuals within the same species
    • For binder, the device file is /dev/binder, with the following information: 10 indicates the primary device number and 58 indicates the secondary device number
    crw-rw-rw- 1 root   root    10,  58 2020-12-02 22:52 binder
    Copy the code
  5. After any driver is written, it needs to register with the kernel so that system calls such as open/ IOCtl can execute methods in the driver. Registration is usually written in an initialization function called xx_init
  6. Misc equipment: The primary device id is 10. You can register the device with the system by calling misc_register
    • Binders are MISC devices
  7. Each method involved in a system call can be commandedman 2|3 <name>View related documents

The system calls

ioctl

Interacts with the driver method, can pass parameters to the driver. Int ioctl(int fd,unsigned long CMD,… ;

  1. CMD is an integer and is divided into several parts, each of which has a different meaning

  2. The third parameter is an address from which the driver copies data using copy_from_user. Such as

    // user call
    flat_binder_object obj {
        .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,
    };
    int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);
    
    // Drive use
    struct flat_binder_object fbo;
    
    if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {}
    Copy the code

mmap

There are two functions:

  1. To realize shared memory, map the same physical memory to different process space

  2. Map ordinary files to memory, and then manipulate the files as if they were read or written to memory. Mmap does not allocate space, but maps files into the address space of the calling process.

    // There is a possibility of failure during the operation
    int fd = open("/Users/xx/Desktop/test", O_RDWR);
    if(fd > 0) {char * mm = (char *)mmap(NULL.8, PROT_READ | PROT_WRITE,
    MAP_SHARED, fd, 0);
        cout << mm << endl;
        // Write data
        cout << strcpy(mm, "foma");
        munmap(mm, 8);
        close(fd);
    }
    Copy the code

copy_from_user

0 is returned, indicating success

Binder uses copy_from_user underneath to copy data from user space to kernel space. So let’s take a look at this method

unsigned long copy_from_user(void * to, const void __user * from, unsigned long n)
Copy the code
  • The first parameter, to, is a pointer to the kernel space’s data target address
  • The second argument, from, is a pointer to the data source address in user space
  • The third argument, n, is the length of the data to copy

If the data copy is successful, zero is returned. Otherwise, return the number of bytes of data that were not copied successfully

copy_to_user

0 is returned, indicating success

Binder uses copy_to_user underneath to return processed data to the caller

unsigned long copy_to_user(void __user *to, const void *from, unsigned long n);
Copy the code
  • To is a pointer to user space,
  • From is the kernel space pointer,
  • N indicates the number of bytes to copy data from kernel space to user space

If the data copy is successful, zero is returned. Otherwise, return the number of bytes of data that were not copied successfully. That is, a return of 0 indicates success

epoll

Underlying the Android Handler mechanism is ePoll, which is a technology for I/O multiplexing. Multiplexing means that a thread can monitor multiple file handles at the same time. Once a file handle is ready, the application can be notified to perform read and write operations. If no file handle is ready, the application will block and surrender the CPU. There are three system call functions associated with epoll: epoll_create/epoll_create1, epoll_ctl, and epoll_wait

Epoll_create: Creates a file descriptor epfd corresponding to epoll. All subsequent operations are based on the return value of this parameter

Epoll_ctl: Adds the file descriptor that the program wants to listen to to epFD

Epoll_wait: Waits for the listening file descriptor to change, blocking the application if it does not. The last parameter is timeout, which can be divided into three cases:

  • -1: waits until a file descriptor enters the ready state
  • 0: Checks if any file descriptors are in the ready state because the current application is not blocked
  • Greater than 0: specifies the blocking time. If a file descriptor is ready during this time, it is returned immediately

The second argument to epoll_wait is the epoll_event array, which the kernel populates with the epoll_event corresponding to the ready FD. Therefore, the epoll_event passed in epoll_ctl is copied into this array when ready.

Using Looper in Android as an example, look at the calls to three methods

/ / stars: : rebuildEpollLocked ()
mEpollFd.reset(epoll_create1(EPOLL_CLOEXEC));

/ / stars: : addFd ()
epoll_ctl(mEpollFd.get(), EPOLL_CTL_ADD, fd, &eventItem);

/ / stars: : pollInner ()
epoll_wait(mEpollFd.get(), eventItems, EPOLL_MAX_EVENTS, timeoutMillis);
Copy the code

Let’s look at the arguments used for the three methods

/ / create
int epfd = epoll_create1(EPOLL_CLOEXEC);

// Add a listener for binder_id
struct epoll_event event;
event.events = EPOLLIN|EPOLLET;// Listen to read and write
event.data.fd = binder_id; // This must be specified
epoll_ctl(epfd, EPOLL_CTL_ADD, binder_id, &event)

// infinite loop, because not only listen once
while(1)
{
    
    // Returns how many file descriptors are ready this time
    // Events from epoll_ctl are copied into this array
    struct epoll_event eventItems[EPOLL_MAX_EVENTS];
    count = epoll_wait(epollfd,eventItems, EPOLL_MAX_EVENTS, - 1);

    for(i = 0; i < count; i++)
    {
        // If binder_id is changed
        if(events[i].data.fd == binder_id)
        {
            // The change is usually read out, possibly to another FD, and also added to the listener using epoll_ctl
        }
        else if(events[i].events & EPOLLIN) // Common fd, can be operated{}}}Copy the code

current

The process currently making the system call

  1. It is actually an alias for a method:#define current get_current()
  2. Every process in Linux is defined by a task_struct data structure. When fork() is used, the kernel regenerates a task_struct object and then inherits some data from the parent process and adds it to the process tree for management

Common Linux functions

Hash table

A hash table is a common hash table in Java. Anything that has an hlist is a hash table

link

Linux divides the classes involved in hash tables into two structures: table headers (which exist in arrays) use hLIST_head, and linked list nodes use hlist_Node. See reference links for various operations on hash tables

Memory allocation function

There are several types of memory allocation functions in Linux, to summarize:

  1. Malloc: Used to allocate memory in user space, not in the kernel, the rest are used in the kernel
  2. Kmalloc: Allocates contiguous memory in the kernel, which requiresThe corresponding physical memory must be continuous and cannot exceed 128 KB
  3. Kzalloc: Based on kmalloc, but forcibly zeroed out the memory region
  4. Vmalloc: Allocates a contiguous block of memory in the kernel, but not necessarily in physical memory
  5. Kcalloc: Specifies the number of elements in the array and the size of each element
  6. Alloc_page: Allocates a page of physical memory and returns the address of the physical memory
  7. Alloc_pages (mask, order) : Allocates 2^ ORDER page physical memory and returns the starting address of physical memory