tag:blogger.com,1999:blog-69032854008412831342024-03-05T02:55:40.675-08:00Sharaf's bloggerSharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.comBlogger5125tag:blogger.com,1999:blog-6903285400841283134.post-41446953890156697232020-07-23T02:47:00.003-07:002020-07-23T02:49:49.912-07:00You can open Mesh Gradients in Krita now!<div dir="ltr" style="text-align: left;" trbidi="on">
<b>TL;DR</b>: meshgradient get rendered in Krita just like you'd expect them to render in other apps<br /><div style="text-align: left;"><br /></div><div style="text-align: left;">Well,
because I couldn't get Bicubic interpolation fully working by the time
of writing and publishing this blog. This part is still in pending state
:(</div><div style="text-align: left;"><br /></div><div style="text-align: left;">Firstly, here are is a screenshot of a complex meshgradient which I found from <a href="https://gitlab.com/Tavmjong/mesh.js/-/blob/master/pepper.svg">Inkscape</a> (I modified it to be Bilinear to get this):<br /></div><div style="text-align: left;"><br /></div><table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: left;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdsR4mNntxc4Cfg9zgYrHopkFCZA-s7kktVDrQnm7JzBAO6tFx_HImVwrHAw38itUhtCw6lGK6AcUCcjKtq9p40sihg7zdlCU9ypiXV01NjI-bOaqWOujfa3dMljKKyFm4iBLtxAs3dKc/s1038/Screenshot_2020-07-23_11-46-06.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1038" data-original-width="960" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdsR4mNntxc4Cfg9zgYrHopkFCZA-s7kktVDrQnm7JzBAO6tFx_HImVwrHAw38itUhtCw6lGK6AcUCcjKtq9p40sihg7zdlCU9ypiXV01NjI-bOaqWOujfa3dMljKKyFm4iBLtxAs3dKc/s320/Screenshot_2020-07-23_11-46-06.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">pepper.svg<br /></td></tr></tbody></table><div style="text-align: left;"><a href="goog_950376765"><br /></a></div><br /><br />As, there isn't much else to say besides giving out the details, I'll jump straight to the technicalities :-)<br /><br /><h3 style="text-align: left;">Technicalities</h3><h4 style="text-align: left;">Rendering (Bilinear)</h4></div><div dir="ltr" style="text-align: left;" trbidi="on">I
started with reading the algorithm mentioned in the specs sheet i.e
Divide And Conquer. I had some confusions about it, but thanks to my
mentors. I got the idea. Then, to implement this algorithm, the idea was
to subdivide the patches, until the difference between the corners is
small enough.<br /><br />Now the question was, how am I going to divide the
surface. Luckily, there was a paper, one search away, which I picked up.
I read it quickly and started writing the algorithm on paper.
Somethings didn't quite make sense, but as I later found out that they
were probably misprints.<br /><br />So, as I implemented the algorithm, the
first thing that I tried to open was this, to check if the subdivision
algorithm was right. Comparing this to Inkscape, it was pretty accurate
(not the color, but the surface itself).<br /><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX1kqqkFh0E64B-u6YY_iss5gDmVuCXbRMJ4alsKvjZYXJl2HBmXNytD-OqFdRk34WL2K8biy1gdXIYgYp3ij3zn91b_nZFWJGm956r8FBMXMUuK3vQHHwNvLTUTUcSO7dOL6046QCpTg/s1920/Screenshot_2020-06-28_20-02-37.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1018" data-original-width="1920" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjX1kqqkFh0E64B-u6YY_iss5gDmVuCXbRMJ4alsKvjZYXJl2HBmXNytD-OqFdRk34WL2K8biy1gdXIYgYp3ij3zn91b_nZFWJGm956r8FBMXMUuK3vQHHwNvLTUTUcSO7dOL6046QCpTg/w625-h333/Screenshot_2020-06-28_20-02-37.png" width="625" /></a><br /><div style="text-align: left;"><br /></div><div style="text-align: left;">Next,
get colors for the new corners was simple too. You could get it by
dividing it in half (we get this from the fact that the surface is
Bilinear). Then just mix them when difference is less than the tolerance
and you get this:</div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVwvD2IVNQwCQPqmwUXLWgzuOyv2aEFONmhkz9UsgfeKF89DElUJwssoFd03Uw8CIqS_pqZNJJAfGDpEhfHcR_jyu4seSwiVknGUA8tCXZ4dUmDmIqlOSym0Ph-D-sdgI9iKgiE1W2Ang/s672/mesh-patch219.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="672" data-original-width="581" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiVwvD2IVNQwCQPqmwUXLWgzuOyv2aEFONmhkz9UsgfeKF89DElUJwssoFd03Uw8CIqS_pqZNJJAfGDpEhfHcR_jyu4seSwiVknGUA8tCXZ4dUmDmIqlOSym0Ph-D-sdgI9iKgiE1W2Ang/s320/mesh-patch219.png" /></a></div><div style="text-align: left;"><br /></div><h4 style="text-align: left;"><br /></h4><h4 style="text-align: left;">Caching</h4><div>Because rendering meshgradients is expensive and anything e.g a simple translation would call for a complete redraw. I had to write a way for poor man's caching. Instead of painting directly on a the canvas. I would first paint on QImage and then paint it on QPainter. <br /></div><div><br /></div><div>Simple enough! However, there was a problem, rendering on QImage and then on scaled up QPainter made things look very pixelated because of scaling. So, to counteract this, my solution was to paint on scaled up QImage i.e scale it up by the same factor as the QPainter. This made everything a whole lot better.</div><br /><h4 style="text-align: left;">Rendering (Bicubic Interpolation)</h4>This
has been the hardest part about this GSoC (till now). The way I usually write code is, I write everything in a bit messy way till I get something
running. Then I come back and check if something could be written in a
better way (read efficiency and readability). This approach went horribly
wrong as I probably had made mistakes and my render was pure chaos and
nowhere close to what you call interpolation. Then I git stashed everything
and started over in a more manageable way, now the interpolation was
working. But turns out, it was an exact replica of the Bilinear
interpolation, but slower (because it did actually calculate derivatives
and what not).<br /><br />So, I asked for help. But then I
immediately realized that my assumptions were wrong. In short, I was
calculating derivatives incorrectly. I quickly modified the code in the
dirty way and finally I could see a smooth render with no Mach Banding.
Unfortunately, this too is based on an assumption, which is not correct
for the all cases. So, Bicubic interpolation works neatly for Mesh Patches which are relatively linear. But falls out of place
for a more messy (generic case) ones. <br /></div><div dir="ltr" style="text-align: left;" trbidi="on">But why? The problem here is with the way I
do subdivision, it is only valid for linear Coons patches. I haven't written the code to subdivide a Bicubic surface. That isn't the only problem, subdividing Bicubic surface is an expensive operation as well. So, I'll have to find a middle ground.</div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on"><br /><h4 style="text-align: left;"><b>Saving</b></h4>Since I spent a lot of time on getting Bicubic Interpolation to work, for a context switch I moved to the next milestone.<br /></div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on">So, I tried to implement the saving operation. Thanks to all the abstractions! This was pretty straightforward to implement.</div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on">I will now write tests for it and the final rendering :)</div><div dir="ltr" style="text-align: left;" trbidi="on"><br /></div><div dir="ltr" style="text-align: left;" trbidi="on">That's all I have for now, hopefully I'll post an update when I get the Bicubic shading working :)<br /></div><div style="text-align: left;" trbidi="on"><br /><h4>Bugs</h4><div>...while rendering<br /></div></div><div style="text-align: left;" trbidi="on"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEyK9TQGL_CG-7mL-PjVODsb2h3G1E1x-0vWXjIwVzJ5eWnrBezB96sHdq6nHj6kFbB5Y1d2nNKitkIco4VXUVuxwyNE2OdE0UFG4Y5DwnrJFFApENl2B2iQw7wNw7eYIe7tSI1zXyfOM/s1018/Screenshot_2020-06-28_21-27-00.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1018" data-original-width="960" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEyK9TQGL_CG-7mL-PjVODsb2h3G1E1x-0vWXjIwVzJ5eWnrBezB96sHdq6nHj6kFbB5Y1d2nNKitkIco4VXUVuxwyNE2OdE0UFG4Y5DwnrJFFApENl2B2iQw7wNw7eYIe7tSI1zXyfOM/s320/Screenshot_2020-06-28_21-27-00.png" /></a></div><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnqeVdHaEQOnJgbikvZ5Ki3QmP0dQfz9qM8q6S0Trh3CytBn2D7WFmSoUQoxMfBBW9zhPHWNrjIkMf92rwiqMhw9h1RZiZvRcbEpxgYn239JV_Cz0pIRTEa6ZV5GkPxdrzxNV4SS7Ioic/s1018/Screenshot_2020-06-28_21-48-36.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1018" data-original-width="960" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnqeVdHaEQOnJgbikvZ5Ki3QmP0dQfz9qM8q6S0Trh3CytBn2D7WFmSoUQoxMfBBW9zhPHWNrjIkMf92rwiqMhw9h1RZiZvRcbEpxgYn239JV_Cz0pIRTEa6ZV5GkPxdrzxNV4SS7Ioic/s320/Screenshot_2020-06-28_21-48-36.png" /></a>Sharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.com1tag:blogger.com,1999:blog-6903285400841283134.post-89667776430396619392020-06-16T12:47:00.000-07:002020-06-16T12:47:42.568-07:00Hello once again!<div dir="ltr" style="text-align: left;" trbidi="on"><p>
First of all, sorry for not making a blog post early on during the community bonding period. I couldn't because I was mostly busy with Krita's Android release.
</p>
<p>
Secondly, some of you might remember me from the previous year. I was GSoC student for Krita. Now it is my second time! :-)
</p>
<p>
Finally, to tell a bit about my project. My project is to add support for SVG mesh gradients in Krita and the relevant task is: <a href="https://phabricator.kde.org/T13101">https://phabricator.kde.org/T13101</a> and branch is: <a href="https://invent.kde.org/graphics/krita/-/merge_requests/378">https://invent.kde.org/graphics/krita/-/merge_requests/378</a>
</p>
<h2>Now over on to the interesting stuff!</h2><div>So, let's see what I did the past couple of weeks.<br /></div>
<h3>1. Parsing</h3>
<p>
This is probably going to be easiest and most of us know hows and whats about his. So, we throw any SVG with <code>meshgradient</code> element, in it and Krita understands it now.
</p>
<h3>2. Making a shape out of the path.</h3>
<p>
Now, this turned out to be a bit complicated than I had anticipated, not because this was hard. But because there were a few edge cases which I overlooked. I would fix one edge case, but it would break the other one, classic whack-a-mole. So, I had to do a few rewrites of this tiny '<a href="https://invent.kde.org/graphics/krita/-/blob/sh-zam/T13101-svg-mesh-gradients/libs/flake/svg/SvgMeshPatch.cpp">SvgMeshPatch</a> and <a href="https://invent.kde.org/graphics/krita/-/blob/sh-zam/T13101-svg-mesh-gradients/libs/flake/svg/SvgMeshArray.cpp">SvgMeshArray</a>' component. Finally, I just put it all on paper and got it working for all cases, in a proper manner <b>*</b>.
</p>
<p>The way I started was to manually compare some 'edge case' values to see if they're correct and fit the logic. But, there's so much that an eye can overlook. What I think I should've done is to write unit tests and then handle each edge case respectively. However the good thing is after writing unit tests, I discovered two cases where my logic wasn't right.
</p>
<h3>3. Deeper dive into the technicalities</h3>
<p>
I will try to explain how I did in a bit more detail. If you have any suggestions/critique, you're welcome.
</p>
<p>
In the big picture sense there are two things to consider, when talking about <code>meshgradients</code>, <code>meshpatch</code> and <code>meshrow</code> (which is a linear array of meshpatches). As per the specifications, <code>meshpatch</code> is a Coons Patch, which is just
the shading/fill defined by the interpolation of colors placed on the corners (i.e. edges of the curve).</p>
<p>
Because they can be seen as a two dimensional arrays, creating an array of meshpatches, seems the most logical approach and that's what I did. However there is a slight catch, each patch shares side with other patches. Eg. in case of a gradient with a single row, up to two sides are shared. So, while parsing this had to be taken care of.
</p>
<p>
So, now we have <code>SvgMeshArray</code> which is an array of of <code>SvgMeshPatch</code> and each <code>SvgMeshPatch</code> owns a <code>KoPathShape</code>, which is how the fill boundaries are going to be defined. And that's basically all there's to it for now...<br /></p>
<p>
On a side note, one thing which is in my mind is that because each meshpatch is treated as an individual Shape, there's some duplication with the shared sides. But I think this is an optimization problem, which has to be taken care of, but after rendering :-)
</p>
<p>
Now a couple of obligatory screenshots, just to double check :) <br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilCcFWcoJ7sY79wL0iAGaADozw0ctXBcefhR4zA6Dra1mJTaEAykiRilPlUGYkhxsj3FFGuWliufMr9NdWrV4qp3UqHfLlvMLrahBBRG-0wxgJPxAkitvNcNhL4Qg2H1MRNnh-v78_bm8/s1920/Screenshot_2020-06-16_21-58-26.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1038" data-original-width="1920" height="423" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilCcFWcoJ7sY79wL0iAGaADozw0ctXBcefhR4zA6Dra1mJTaEAykiRilPlUGYkhxsj3FFGuWliufMr9NdWrV4qp3UqHfLlvMLrahBBRG-0wxgJPxAkitvNcNhL4Qg2H1MRNnh-v78_bm8/w781-h423/Screenshot_2020-06-16_21-58-26.png" width="781" /></a></div><p><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WruADIvgGdTLMVzJg6yUsn_c44LXQYsl24x_eCoVpAHhZFDFfVplg3Bj1Xh23-NuAcgMyvqS-wDswbOlNZJ8VS_2kxUPbeI186V1lLfm8qgzLf2DxkPnmOpvk4-mr3MYDsDc6lbVDdg/s1919/Screenshot_2020-06-16_23-46-38.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1001" data-original-width="1919" height="405" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg0WruADIvgGdTLMVzJg6yUsn_c44LXQYsl24x_eCoVpAHhZFDFfVplg3Bj1Xh23-NuAcgMyvqS-wDswbOlNZJ8VS_2kxUPbeI186V1lLfm8qgzLf2DxkPnmOpvk4-mr3MYDsDc6lbVDdg/w781-h405/Screenshot_2020-06-16_23-46-38.png" width="781" /></a></div><p><br /></p><p><br /></p><p><br /></p><p>PS:<br /></p>
<p>
<b>*</b> I in no way consider myself an expert, yet. Feel free to look at the code and comment on it.
</p></div>
Sharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.com0tag:blogger.com,1999:blog-6903285400841283134.post-83838484466580081682019-07-08T12:10:00.000-07:002019-07-08T12:11:43.907-07:00Updates on Krita on android<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Update</title>
<link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>
<body class="stackedit">
<div class="stackedit__html"><p>It has been a long time since I posted a blog (1 month+). In fact it might even seem the Krita ran on Android and now GSoC is done. Well, not quite. There’s still a lot to be done.</p>
<p>Let’s see what we worked on :)</p>
<h3 id="build">Build</h3>
<p>First and foremost was managing the build. If you have a look at <a href="https://invent.kde.org/kde/krita/blob/sh-zam/T10784-android-port/README.android"><code>README.android</code></a>, you will see that’s a bunch of environment variables and few steps. If you look at underlying code, it was even uglier with lots of boiler plate. So, we had to refactor it and we did and made the build system a bit pleasant. (<a href="https://invent.kde.org/kde/krita/commit/4467ad27435fab50be46dad788193252e156acd5"><code>4467ad274</code></a>)</p>
<h3 id="opengl-canvas">OpenGL Canvas</h3>
<p>Next, was a bug in the OpenGL canvas, when we enabled hardware acceleration, the canvas would turn black. <code>QPainter</code> being painfully slow, so it certainly isn’t the option, so we really rely on OpenGL ES.<br>
So we had to fix this, it took me quite some time to fix and the <a href="https://invent.kde.org/kde/krita/commit/60539c690acf">solution</a> was simple in the end.<br>
Results? <a href="https://drive.google.com/open?id=1q8Ee03H7Hvf_-AKevg6V_1RXJdDnylZH">We <em>can</em> draw on OpenGL canvas now!</a></p>
<h3 id="autosave">Autosave</h3>
<p>If you have played any heavy game on Android, then there is one thing which you might know. If you leave the app and come back after a few minutes all the progress is lost or the connection to the server is terminated (it happens less often with new devices having a lot of memory).<br>
This could happens with Krita as well, so now as soon as we get <a href="https://developer.android.com/reference/android/app/Activity.html#onPause()"><code>Activity#onPause()</code></a>, we call the JNI wrapper <a href="https://invent.kde.org/kde/krita/blob/a2bd34cb28774d67f80cf2ce56ee62aa9b640565/krita/main.cc#L145"><code>Java_org_krita_android_JNIWrappers_saveState</code></a> to save the state synchronously.<br>
I did try to save it asynchronously (which uses slots and signal), but I found out, as soon as the main Qt thread was paused, the entire queued connection mechanism was brought to halt.</p>
<h3 id="touch-events">Touch events</h3>
<p>For past week, I have been working on adding touch support to the canvas. What I mean by touch support is, to handle “finger paint” events and we’ve been successful in doing so. We can now draw on canvas now, using our fingers, not just a pen!</p>
<p>To do this we simply consider the touch events with one touch point as mouse click/update/release events (the same way we do this for tablet events).</p>
<p>But… there is a difference!</p>
<p>Krita did support touch drawing on touch screen windows/linux laptops. So, why didn’t it work for android devices? In windows, if <code>QTouchEvent</code> wasn’t handled, Qt would automatically generate <code>QMouseEvent</code> for it. But the same wasn’t true for android.<br>
There is a way, however, to simply ignore touch events and use mouse events, even for android (by manipulating <a href="https://doc.qt.io/qt-5/qtouchevent.html#enabling-touch-events"><code>Qt::WA_AcceptTouchEvents</code></a> flag). This wouldn’t work for Krita because we still use touch events to rotate/zoom/move canvas. So, we now explicitly handle touch events.</p>
<h3 id="rotation">Rotation</h3>
<p>We can now rotate the canvas using gestures! A small clip: <a href="https://drive.google.com/open?id=1-IHHPmvmWU99lmoW72CZ1wBGdMnErlxh">rotation-canvas</a></p>
<p>It was pretty simple as well. First the way <code>KisTouchShortcut::match</code> worked, wouldn’t allow both zooming and rotation to co-exist, because it distinguishes the different <code>KisTouchShortcut</code>s based on number of minimum and maximum touch points. For both zooming and rotating, it was two.</p>
<p>So, for them to work in harmony, I created another class, <code>KisZoomAndRotateAction</code>, which delegates the call to <code>KisZoomAction</code> and <code>KisRotateAction</code>.</p>
<p>Secondly, in <code>KisRotateAction</code>, we just find out the angle between the lines. Line being, “the line” passing through the two touchpoints on the canvas.<br>
So, the two lines are:</p>
<ol>
<li>Initial position of fingers</li>
<li>Final position of fingers</li>
</ol>
<p>(this is a bit hard to explain, please look at code).</p>
<p>Anything else?<br>
Yes, <a href="https://forum.qt.io/topic/104424/how-does-one-debug-libqtforandroid">this</a>.</p>
<p>That's all! Thank you for reading, I’ll try to be more regular with my blog now :)</p>
</div>
</body>
</html>
Sharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.com0tag:blogger.com,1999:blog-6903285400841283134.post-33419315045676591202019-05-28T07:31:00.000-07:002019-05-28T07:31:12.943-07:00Debugging Krita on Android<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Debugging Krita on Android</title>
<link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>
<body class="stackedit">
<div class="stackedit__html"><p>Well, the easiest way is to use <a href="https://developer.android.com/studio">Android Studio</a>.</p>
<p>Import the project in Android Studio as a <code>gradle</code> project and build the project. Krita build <em>will</em> fail when run from Android Studio. Now, to run it successfully, we’ll have to manually provide the path to <a href="https://invent.kde.org/kde/krita/blob/660972c3835b022d8e0816ee65e60e75568ef0af/packaging/android/apk/build.gradle#L25"><code>installPrefix</code></a> or comment out <code>copyLibs</code> <a href="https://invent.kde.org/kde/krita/blob/660972c3835b022d8e0816ee65e60e75568ef0af/packaging/android/apk/build.gradle#L104">dependency</a>. Now, the project <em>should</em> build properly.</p>
<p>You might want to <a href="https://developer.android.com/studio/debug#debug-types">change the debug type</a> to <strong><code>Native</code></strong> or <strong><code>Dual</code></strong>, as their <strong><code>Auto</code></strong> mode did not work for me. Open the C++ file in Android Studio and set a breakpoint. Click the bug icon, sit back and watch while Android Studio does all the magic for you.</p>
<p>And then it is usual <code>lldb</code> (in Android Studio) or GUI if that’s what you prefer.</p>
<h3 id="using-command-line">Using command line:</h3>
<p>Starting Android studio takes a lot of time and memory. Then, it builds which takes an additional few minutes, so it really isn’t a good idea to use it for debugging every time the app crashes. So, the less time consuming one and a bit complex method – here we go!</p>
<p>Assuming the app has been installed with the debug key. The first step is to launch it in debug mode, to do so:</p>
<pre class=" language-shell"><code class="prism language-shell"># domain/(launcher activity or exported activity's class-path)
$ adb shell am start -D -n "org.kde.krita/org.krita.android.MainActivity"
</code></pre>
<p>Now the app on phone should launch and show <code>Waiting for Debugger</code> message. While it waits – open a terminal and enter <code>$ adb shell</code>, and then look for <code>lldb-server</code> in <code>/data/local/tmp/</code>. If you ever debugged app through Android Studio, then it <em>should</em> exist. If it does not, then launch Android Studio and run it in debug mode 😂…hahahaha.</p>
<p>Just kidding, push the file to that location.</p>
<pre class=" language-shell"><code class="prism language-shell">$ adb push $ANDROID_SDK_ROOT/lldb/<version>/android/<abi>/lldb-server /data/local/tmp
$ adb shell chmod +x /data/local/tmp/lldb-server
</code></pre>
<p><sub>(No <code>lldb</code> directory? See notes)</sub></p>
<p>Then for us to access the libraries, we’ll have to copy it to <code>/data/data/org.kde.krita</code>, for that:</p>
<pre class=" language-shell"><code class="prism language-shell">$ adb shell run-as org.kde.krita cp /data/local/tmp/lldb-server /data/data/org.kde.krita
</code></pre>
<p>(Why <code>run-as</code>? It is a <code>setuid</code> program and gives us the necessary permission to access <a href="https://source.android.com/security/app-sandbox">the sandbox</a>).</p>
<p>Now, enter the app sandbox by first entering the <code>$ adb shell</code> and then <code>$ run-as org.kde.krita</code>.</p>
<p>Run the <code>lldb-server</code> like you would if you were remote debugging.</p>
<pre class=" language-shell"><code class="prism language-shell">$ ./lldb-server platform --server --listen "<incoming-ip>:<port>"
$ # Example: allow any ip on port 9999
$ ./lldb-server platform --server --listen "*:9999"
</code></pre>
<p>Now on the host machine, run <code>lldb</code> and then</p>
<pre class=" language-shell"><code class="prism language-shell">(lldb) platform select remote-android
(lldb) platform connect connect://<ip>:<port>
</code></pre>
<p>On my machine:</p>
<pre class=" language-lldb"><code class="prism language-lldb">(lldb) platform select remote-android
Platform: remote-android
Connected: no
(lldb) platform connect connect://localhost:9999
Platform: remote-android
Triple: arm-*-linux-android
OS Version: 28.0.0 (4.4.153-15659493)
Kernel: #2 SMP PREEMPT Thu Apr 4 18:31:57 KST 2019
Hostname: localhost
Connected: yes
WorkingDir: /data/data/org.kde.krita
</code></pre>
<p>You can read more about what they do on <a href="https://lldb.llvm.org/use/remote.html">LLVM’s website</a>.<br>
(This is one a time setup you can keep the server and client connected)</p>
<p>Remember, that our process is still <code>Waiting for Debugger</code>? :(<br>
Let’s give it what it wants. Attach the debugger to the running process’s pid, which can be known by <code>$ adb shell ps | grep "krita"</code> or <code>$ pgrep "krita"</code></p>
<p>To attach:</p>
<pre class=" language-shell"><code class="prism language-shell">(lldb) attach <pid>
(lldb) # on my machine
(lldb) attach 1818
Process 1818 stopped
* thread #1, name = 'org.kde.krita', stop reason = signal SIGSTOP
frame #0: 0xe8d35f7c libc.so`syscall + 28
<and much more>
</code></pre>
<p>Still didn’t continue? :-<<br>
So, let’s <strong>finally</strong> resume it!</p>
<p>We’ll have to resume it over Java Debug Wire Protocol (JDWP), we’ll use <code>jdb</code></p>
<pre class=" language-shell"><code class="prism language-shell">$ adb forward tcp:12345 jdwp:<pid> # the same pid which we attached in lldb
$ jdb -attach localhost:12345
</code></pre>
<p>Now <code>continue</code> the process in <code>lldb</code> and we are done!</p>
<p>(This might seem like a lot, but it really isn’t. Every time the app crashes, I run in debug mode <code>$ attach pid</code> and I get the backtrace immediately!)</p>
<p><sub>PS: When I was looking for it on the internet, I didn’t find much about it and had to spend a lot of time on this.<br>
This method <em>should</em> work with debugging any android app with <code>lldb</code>, obv!<br>
(I am really new to blogging. If it’s hard to understand or my formatting is bad, I am really sorry.)<br>
</sub></p>
<h3 id="notes">Notes</h3>
<ul>
<li>I hate the extra <code>jdb</code> thing, and if the function which you want to debug is not going to be called during the early start up, you can use <code>-N</code> flag instead of <code>-D</code> with <code>am</code>.</li>
<li>Can’t find <code>lldb</code> directory in your SDK? Use platform tools to install it.</li>
<li><code>jdb</code> doesn’t attach? <code>$ killall android-studio && adb kill-server #_#</code></li>
</ul>
<h4 id="resources">Resources</h4>
<p><a href="https://source.android.com/devices/tech/debug/gdb">https://source.android.com/devices/tech/debug/gdb</a><br>
<a href="https://android.googlesource.com/platform/ndk/+/master/ndk-gdb.py">https://android.googlesource.com/platform/ndk/+/master/ndk-gdb.py</a><br>
<a href="https://lldb.llvm.org/use/remote.html">https://lldb.llvm.org/use/remote.html</a></p>
</div>
</body>
</html>Sharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.com5tag:blogger.com,1999:blog-6903285400841283134.post-60327682378070341692019-05-14T08:55:00.000-07:002019-12-21T01:41:35.066-08:00Hello KDE<div dir="ltr" style="text-align: left;" trbidi="on">
Hello, my name is Sharaf. My nick on IRC is <b>sh_zam.</b><br />
<br />
My project is to port Krita to android devices. We've been successful in making the <a href="https://twitter.com/Krita_Painting/status/1127163934820196354">APK</a>, but it only works if <i>I</i> build it, as it requires tweaking qt libraries, a bit. At the moment, my goal is to make the build system fully automatic and spit out the signed APKs for different architectures at the end.<br />
<br />
Once I do that, I'll move on to UI, events and other fun stuff!<br />
<br />
So, there's a lot to do and learn. Now I will go back to coding. (-:<br />
<br />
So, thank you KDE for choosing me and I hope I'll learn a lot from this community!</div>
Sharaf Zamanhttp://www.blogger.com/profile/14747861187357073047noreply@blogger.com2