Android-System-ServiceManager1

Inhaltsverzeichnis

Einführung

Konzept

Start-up

Flussdiagramm

hauptsächlich

binder_open

binder_become_context_manager

binder_ioctl

binder_ioctl_set_ctx_mgr

binder_new_node

binder_loop

binder_write

binder_ioctl

binder_ioctl_write_read

binder_thread_write

binder_parse

bio_init

bio_init_from_txn

svcmgr_handler

svcinfo

Abfragedienst

do_find_service

find_svc

bio_put_ref

bio_alloc_obj

bio_alloc

do_add_service

Registrierungsservice

svc_can_register

svcinfo_death

bio_get_ref

binder_ioctl_write_read

binder_thread_write

binder_thread_read


Einführung

ServiceManager ist ein Daemon-Prozess in der Binder IPC-Kommunikation, der zur Realisierung der Binder IPC-Kommunikation dient. ServiceManager selbst ist also ein Dienst und ein Bindemitteldienst.

ServiceManager weist zwei Merkmale auf:

1. Anstatt das Multithread-Modell in libbinder für die Kommunikation mit dem Binder-Treiber zu verwenden, kommuniziert es direkt mit dem Binder-Treiber über die sicher geschriebene binder.c, und es gibt nur eine Schleife binder_loop zum Lesen und Verarbeiten von Transaktionen Halten Sie es einfach und effizient

2. Es gibt zwei Hauptfunktionen von ServiceManager: Registrierungsdienst und Abfragedienst.

Konzept

ServiceManager-Startvorgang (vereinfachte Version):

1) Öffnen Sie den Binder-Treiber

2) Registrieren Sie sich als Kontextmanager

3) Geben Sie den Schleifenzyklus ein und verarbeiten Sie Transaktionen

Die beiden Kernfunktionen von ServiceManager:

Dienst registrieren: Dienstnamen und Handler aufzeichnen, in der svclist-Liste speichern

Abfragedienst: Fragen Sie die entsprechenden Handlerinformationen gemäß dem Dienstnamen ab

Start-up

Flussdiagramm

Framework/native/cmds/servicemanager/

- service_manager.c

- Bindemittel.c

kernel/drivers/ (verschiedene Linux-Zweigpfade unterscheiden sich geringfügig)

- android/binder.c

ServiceManager wird vom Init-Prozess erstellt

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    onrestart restart keystore
    onrestart restart gatekeeperd
    onrestart restart thermalservice
    writepid /dev/cpuset/system-background/tasks
    shutdown critical

hauptsächlich

int main(int argc, char** argv)
{
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;

    if (argc > 1) {
        driver = argv[1];
    } else {
        driver = "/dev/binder";
    }

    bs = binder_open(driver, 128*1024);
    if (!bs) {
#ifdef VENDORSERVICEMANAGER
        ALOGW("failed to open binder driver %s\n", driver);
        while (true) {
            sleep(UINT_MAX);
        }
#else
        ALOGE("failed to open binder driver %s\n", driver);
#endif
        return -1;
    }

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
    cb.func_log = selinux_vendor_log_callback;
#else
    cb.func_log = selinux_log_callback;
#endif
    selinux_set_callback(SELINUX_CB_LOG, cb);

#ifdef VENDORSERVICEMANAGER
    sehandle = selinux_android_vendor_service_context_handle();
#else
    sehandle = selinux_android_service_context_handle();
#endif
    selinux_status_open(true);

    if (sehandle == NULL) {
        ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
        abort();
    }

    if (getcon(&service_manager_context) != 0) {
        ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
        abort();
    }


    binder_loop(bs, svcmgr_handler);

    return 0;
}

ServiceManager-Startvorgang (allgemeine Version):

1) Öffnen Sie den Binder-Treiber und rufen Sie die mmap-Methode auf, um 128 KB Speicherzuordnungsraum zuzuweisen: binder_open

2) Registrieren Sie sich als Kontextmanager: binder_become_context_manager

3) Überprüfen Sie die Selinux-Berechtigungen, um festzustellen, ob der Prozess die Berechtigung hat, bestimmte Dienste zu registrieren oder anzuzeigen

4) Betreten Sie die Schleife und warten Sie auf die Anfrage des Clients: bind_loop

binder_open

struct binder_state
{
    int fd;
    void *mapped;
    size_t mapsize;
};

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
   struct binder_state *bs;
    struct binder_version vers;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }

    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open %s (%s)\n",
                driver, strerror(errno));
        goto fail_open;
    }

    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr,
                "binder: kernel driver version (%d) differs from user space version (%d)\n",
                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
        goto fail_open;
    }

    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}

void binder_close(struct binder_state *bs)
{
    munmap(bs->mapped, bs->mapsize);
    close(bs->fd);
    free(bs);
}

Der Benutzerbereich ruft die offene Methode des Treibers über die offene Methode auf, erstellt ein binder_proc-Strukturobjekt, weist dann das binder_proc-Objekt fd->private_data zu und fügt es in die globale verknüpfte Liste binder_procs ein

Die Binder-Version des Treibers kann über ioctl(bs->fd, BINDER_VERSION, &vers) abgerufen werden.

Rufen Sie mmap() für die Speicherzuordnung auf. In ähnlicher Weise wird die mmap()-Methode vom System aufgerufen und entspricht der binder_mmap()-Methode der Binder-Treiberebene. Diese Methode erstellt ein Binder_buffer-Objekt in der Binder-Treiberebene und fügt es ein die proc->buffers der aktuellen verknüpften Liste binder_proc.

int fd; // Dateideskriptor von dev/binder

void *mapped; //Zeigen Sie auf die Speicheradresse von mmap

size_t Mapsize; // Die zugewiesene Speichergröße, der Standardwert ist 128 KB

binder_become_context_manager

Seien Sie der Manager des Kontexts, und im gesamten System gibt es nur einen solchen Manager. Durch den Systemaufruf über die Methode ioctl () entspricht es der Methode binder_ioctl () der Binder-Treiberschicht.

binder_ioctl

Gemäß dem Parameter BINDER_SET_CONTEXT_MGR wird schließlich die Methode binder_ioctl_set_ctx_mgr () aufgerufen, und dieser Prozess hält binder_main_lock.

binder_ioctl_set_ctx_mgr

Das globale binder_node-Objekt binder_context_mgr_node wird erstellt und die starken und schwachen Referenzen von binder_context_mgr_node werden um 1 addiert.

binder_new_node

Erstellen Sie ein binder_node-Strukturobjekt in der Binder-Treiberebene und fügen Sie den aktuellen binder_proc zum Knoten->proc von binder_node hinzu. Und erstellen Sie zwei Warteschlangen mit binder_node async_todo und binder_work.

binder_loop

Geben Sie den Lese- und Schreibvorgang der Schleife ein. Der von der Methode main () übergebene Parameter func zeigt auf svcmgr_handler.

binder_write sendet den Befehl BC_ENTER_LOOPER über ioctl () an den Binder-Treiber. Zu diesem Zeitpunkt hat bwr nur Daten im write_buffer und ruft die Methode binder_thread_write () auf. Geben Sie als Nächstes die for-Schleife ein und führen Sie ioctl () aus. Zu diesem Zeitpunkt enthält nur read_buffer Daten im BWR, und geben Sie dann die Methode binder_thread_read () ein.

binder_write

Initialisieren Sie gemäß den übergebenen Parametern bwr, wobei write_size 4 ist, write_buffer auf die Startadresse des Puffers zeigt und sein Inhalt die BC_ENTER_LOOPER-Anforderungsprotokollnummer ist. Senden Sie die BWR-Daten über ioctl an den Binder-Treiber und rufen Sie dann dessen Methode binder_ioctl wie folgt auf:

binder_ioctl

binder_ioctl_write_read

binder_thread_write

Nehmen Sie die cmd-Daten aus bwr.write_buffer heraus, hier ist BC_ENTER_LOOPER. Es ist ersichtlich, dass die obere Ebene dieses Mal die Methode binder_write() aufruft, hauptsächlich um die Einstellung des Looper-Status des aktuellen Threads als BINDER_LOOPER_STATE_ENTERED abzuschließen.

binder_parse

Analysieren Sie die Binderinformationen, wobei der Parameter ptr auf BC_ENTER_LOOPER und func auf svcmgr_handler zeigt. Wenn daher eine Anfrage kommt, wird svcmgr_handler aufgerufen.

bio_init

bio_init_from_txn

svcmgr_handler

Funktionen dieser Methode: Dienste abfragen, Dienste registrieren und alle Dienste auflisten

svcinfo

Jeder Dienst wird durch die svcinfo-Struktur dargestellt, und der Handle-Wert wird durch das Ende des Prozesses bestimmt, in dem sich der Dienst während des Registrierungsprozesses des Dienstes befindet.

Abfragedienst

do_find_service

Fragen Sie den Zieldienst ab und geben Sie das dem Dienst entsprechende Handle zurück

find_svc

Überprüfen Sie anhand der svclist-Dienstliste, ob er entsprechend dem Dienstnamen registriert wurde. Wenn der Dienst bereits in svclist vorhanden ist, wird der entsprechende Dienstname zurückgegeben, andernfalls wird NULL zurückgegeben.

Wenn das Handle des Dienstes gefunden wird, rufen Sie bio_put_ref(reply, handle) auf, um das Handle in die Antwort einzukapseln.

bio_put_ref

bio_alloc_obj

bio_alloc

do_add_service

Registrierungsservice

Der Registrierungsservice gliedert sich in die folgenden 3 Teile:

  • svc_can_register: Überprüfen Sie die Berechtigungen und prüfen Sie, ob die Selinux-Berechtigungen erfüllt sind.
  • find_svc: Dienstabruf, Abfrage des passenden Dienstes anhand des Dienstnamens;
  • svcinfo_death: Geben Sie den Dienst frei. Wenn ein Dienst mit demselben Namen gefunden wird, werden zuerst die Dienstinformationen gelöscht und dann wird der aktuelle Dienst zur Dienstliste svclist hinzugefügt.

svc_can_register

svcinfo_death

bio_get_ref

binder_write: Rufen Sie nach Eingabe des Binder-Treibers direkt binder_thread_write auf, geben Sie ihn ein und verarbeiten Sie den Befehl BC_REQUEST_DEATH_NOTIFICATION

binder_ioctl_write_read

binder_thread_write

Der Prozess und der Thread in dieser Methode beziehen sich auf die Informationen des aktuellen Servicemanager-Prozesses. Wenn sich zu diesem Zeitpunkt Daten in der TODO-Warteschlange befinden, geben Sie binder_thread_read ein.

In welchen Szenarien werden also BINDER_WORK_DEAD_BINDER-Transaktionen zur Warteschlange hinzugefügt? Das heißt, wenn der Prozess, in dem sich der Binder befindet, stirbt, wird die Methode binder_release aufgerufen, und dann wird binder_node_release aufgerufen. Dieser Prozess sendet einen Rückruf für die Todesbenachrichtigung.

binder_thread_read

Schreiben Sie den Befehl BR_DEAD_BINDER in den Benutzerbereich, wo das Cookie der zuvor übergebene svcinfo_death ist. Die Nachricht wird verarbeitet, wenn binder_loop das nächste Mal binder_parse ausführt.

Supongo que te gusta

Origin blog.csdn.net/haigand/article/details/132248247
Recomendado
Clasificación